JAVA后端面试《Spring》

Spring

  1. Spring是什么?有什么好处?
  2. IOC是什么?有什么好处?简单过程?
  3. DI是什么?
  4. IOC和DI的关系?
  5. bean标签的属性有哪些?
  6. IOC创建对象有哪几种方式?
  7. Spring是如何实现IOC的?也就是如何创建对象的?
  8. Spring Bean的生命周期?
  9. 依赖注入DI的方式有几种?
  10. 注解实现IOC和DI的准备工作有哪些?
  11. 有哪些注解?分别表示什么含义?
  12. 谈谈你对Spring AOP的理解?
  13. XML方式实现AOP的通知有几种?
  14. 注解实现AOP的过程?
  15. 更改多个切面类的执行顺序的方法有几种?
  16. Spring有哪些主要模块?
  17. Spring中的bean是线程安全的吗?
  18. Spring支持几种bean的作用域?
  19. Spring JDBC的实现过程?
  20. 事务的概念是什么?
  21. 事务的特性有几个?
  22. 数据库操作时可能存在的问题有哪些?
  23. 什么是事务的隔离级别?事务的隔离级别有几个?
  24. Spring中事务的传播行为有几种?
  25. Spring 声明式事务的实现?

1.Spring是什么?有什么好处?

概念:SPring是一个支持控制反转(IOC)和面向切面编程(AOP)的容器框架。
好处:两降低>>>两支持>>>两方便

  • ①降低了耦合性,提高了开发速度。
  • ②降低了JAVAEE API的使用难度。
  • ③支持AOP和IOC。
  • ④支持声明式事务。
  • ⑤方便程序测试。
  • ⑥方便集成其他框架。

2.IOC是什么?有什么好处?简单过程?

IOC:是Inverse of Control(控制反转)的简写。
好处:通过IOC,直接把对象创建的权力反转给Spring容器,降低了对象之间的耦合性。
简单过程:程序读取Spring的XML配置文>>>获取需要创建对象的bean>>>通过反射机制创建对象的实例。

3.DI是什么?

DI:Dependency Injection(依赖注入)的简写。
创建对象实例时,同时为对象注入它所依赖的属性,相当于把每个bean和bean之间的关系交给Spring容器来管理。

4.IOC和DI的关系?

控制反转(IOC)和依赖注入(DI)是从不同角度描述同一件事情,利用依赖关系注入的方式,实现对像之间的解耦。
耦合性(耦合度):是对模块间关联程度的度量。模块之间联系越紧密,其耦合性就越高,模块之间越独立则越低。

5.bean标签的属性有哪些?

  • ① id (唯一标识)
  • ② name(获取bean的键)
  • ③ class(指定bean对应类的全路径)
  • ④ scope(单例或者多例设计模式)
  • ⑤ lazy-init(延时加载,默认值:false):设置false时,只有调用getBean方法才会创建对象
  • ⑥ init-method(指定:监听对象创建的方法)
  • ⑦ destroy-method(指定:监听对象销毁的方法)

6.IOC创建对象有哪几种方式?

  • ①无参构造
  • ②有参构造
  • ③静态工厂模式(1个bean标签)
  • ④非静态工厂模式(2个bean标签)
//1.无参构造
   <bean id="user" class="com.wpq.pojo.User"></bean>
  //在bean标签内部使用property标签,相当于调用set方法. name:要赋值的属性的属性名 value:值
   <bean id="user" class="com.wpq.pojo.User">
        <property name="name" value="zs"></property>
        <property name="password" value="123"></property>
   </bean>
                 
//2.有参构造
 <bean id="user" class="com.wpq.pojo.User">
     <constructor-arg index="0" type="java.lang.String" name="name" value="张三"></constructor-arg>
     <constructor-arg index="1" type="java.lang.String" name="password" value="123"></constructor-arg>
 </bean>
//3.静态工厂模式--createPerson()为静态方法
<bean name="personFactory" class="com.wpq.factory.PersonFactory" factory-method="createPerson"/>
//4.工厂模式
  <!--1.创建出工厂对象-->
  <bean name="personFactory" class="com.wpq.factory.PersonFactory"/>
  <!--2.调用工厂的instancePerson()方法创建出Person对象-->
  <bean name="person" factory-bean="personFactory" factory-method="instancePerson"/>

7.Spring是如何实现IOC的?也就是如何创建对象的?

    <!--0.对象创建原理:xml解析+反射-->
    <!--1.ClassPathXmlApplicationContext根据xml的路径和名称加载xml;-->
    <!--2.对该xml文件进行解析-->
    <!--3.根据class属性,获取class属性的值:com.wpq.domain.Person-->
    <!--4.反射:获取字节码的方式,Class clazz=Class.forName("全路径");p.getClass();Person.class-->
    <!--5.根据字节码创建对象:Person p=clazz.newInstance()-->
    <!--6.给对象里的属性赋值:Fields[] fields=clazz.getDeclaredFields();-->
    <!--7.遍历属性数组:for(Field field : fields){ field.setAccessable(true);field.set(30)}-->
    <bean id="person" class="com.wpq.domain.Person">
        <property name="name" value="zs"/>
        <property name="age" value="30"/>
    </bean>

8.Spring Bean的生命周期?

  • ①实例化 Instantiation
  • ②属性赋值 Populate
  • ③初始化 Initialization
  • ④销毁 Destruction

9.依赖注入DI的方式有几种?

  • ①set方法注入
<bean id="user" class="com.wpq.pojo.User">
        <property name="name" value="zs"></property>
        <property name="password" value="123"></property>
</bean>
  • ②构造函数注入
<bean id="user" class="com.wpq.pojo.User">
     <constructor-arg index="0" type="java.lang.String" name="name" value="张三"></constructor-arg>
     <constructor-arg index="1" type="java.lang.String" name="password" value="123"></constructor-arg>
 </bean>
  • ③P命名空间注入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--第3种注入方式:p命名空间,记得引入一个命名空间字符串:xmlns:p="http://www.springframework.org/schema/p"-->
    <!--p:property的缩写!简化了set方式注入的代码编写-->
   <bean name="car" class="com.wpq.domain.Car" p:logo="马车" p:color="黑色"/>
   <bean name="person" class="com.wpq.domain.Person" p:name="阮小二" p:age="40" p:car-ref="car"/>
</beans>
  • ④spel表达式注入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--4.第4种spel表达式来注入值-->
    <bean name="car" class="com.syc.spring.domain.Car">
        <property name="logo" value="劳斯莱斯"/>
        <property name="color" value="黑色"/>
    </bean>

    <bean name="person" class="com.wpq.domain.Person">
        <!--spel语法:#{变量名称}-->
        <property name="name" value="#{car.logo}"/>
    </bean>
</beans>
  • ⑤复杂类型(集合)注入
package com.wpq.domain;

import java.util.*;

/**
 * 集合类型赋值
 */
public class CollectionBean {

    //array节点
    private Object[] arr;

    //list节点
    private List list;

    //map节点
    private Map map;

    //set节点
    private Set set;

    //Properties:配置属性,props节点
    private Properties props;

    public Object[] getArr() {
        return arr;
    }

    public void setArr(Object[] arr) {
        this.arr = arr;
    }

    public List getList() {
        return list;
    }

    public void setList(List list) {
        this.list = list;
    }

    public Map getMap() {
        return map;
    }

    public void setMap(Map map) {
        this.map = map;
    }

    public Set getSet() {
        return set;
    }

    public void setSet(Set set) {
        this.set = set;
    }

    public Properties getProps() {
        return props;
    }

    public void setProps(Properties props) {
        this.props = props;
    }

    @Override
    public String toString() {
        return "CollectionBean{" +
                "arr=" + Arrays.toString(arr) +
                ", list=" + list +
                ", map=" + map +
                ", set=" + set +
                ", props=" + props +
                '}';
    }

}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--5.第5种注入方式:复杂(集合)类型注入-->
    <bean name="cb2" class="com.wpq.domain.CollectionBean">
        <property name="arr">
            <array>
                <value>李师师</value>
                <value>柳如是</value>
                <value>苍老师</value>
            </array>
        </property>
    </bean>

    <bean name="cb3" class="com.wpq.domain.CollectionBean">
        <property name="list">
            <list>
                <value>大乔</value>
                <value>小乔</value>
                <value>金莲</value>
            </list>
        </property>
    </bean>

    <bean name="cb4" class="com.wpq.domain.CollectionBean">
        <property name="map">
            <map>
                <entry key="name" value="三胖"/>
                <entry key="age" value="30"/>
                <entry key="job" value="boss"/>
            </map>
        </property>
    </bean>

    <bean name="cb5" class="com.wpq.domain.CollectionBean">
        <property name="set">
           <set>
               <value>大乔</value>
               <value>小乔</value>
               <value>金莲</value>
           </set>
        </property>
    </bean>

    <bean name="cb6" class="com.wpq.domain.CollectionBean">
        <property name="props">
            <props>
                <prop key="url">jdbc:mysql://localhost:3306/db01</prop>
                <prop key="driver">com.jdbc.mysql.Driver</prop>
                <prop key="username">root</prop>
                <prop key="password">root</prop>
            </props>
        </property>
    </bean>

</beans>

10.注解实现IOC和DI的准备工作有哪些?

  • ① 在XML文件中引入Context的约束
  • ② 配置组件扫描器
  • ③使用注解
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
     <!--1.在XML文件中引入Context的约束-->
    <!--2.配置组件扫描器:去指定的包里面扫描要创建的对象-->
    <context:component-scan base-package="com.wpq.domain,com.wpq.web,com.wpq.service,com.wpq.dao"/>
</beans>

11.有哪些注解?分别表示什么含义?

  • ①注解实现IOC
    • @Component:组件注解,用来创建一个对象,等同于在xml中写了bean标签。
  • ②注解实现DI
    • @Value("…"): 只能给简单类型注入值,不能给引用类型注入值,使用在成员变量上或set方法上 (简单类型=String+8种基本类型)
    • 注意:该注解可以引入配置文件中的变量。 语法: @Value("$")
实现步骤: 1. 创建conf.properties配置文件(age=11,name=wpq)
2. XML中配置property-placeholder加载配置文件 -->
<!--用来去某个指定的位置下,加载指定名称的配置文件-->
<!--会把这个properties文件转换为一个Properties类-->
<context:property-placeholder location="classpath:conf.properties"/>
  • ③ Bean标签的属性对应的注解
    作用域: @Scope(scopeName=“单例/多例”)
    延迟加载:@Lazy: 等同于中的lazy-init属性 ,设置是否延迟加载
    创建对象监听:@PostConstruct 指定监听对象创建的方法
    销毁对象监听:@PreDestroy 指定监听对象销毁的方法
  • ④ 组件注解
    • @Component:组件注解
    • @Controller:组件注解,一般用于web层对象的创建
    • @Service:组件注解,一般用于service层对象的创建
    • @Repository:组件注解,一般用于dao层对象的创建
  • ⑤ 测试注解
    • @RunWith(SpringJUnit4ClassRunner.class) :括号内指定完成测试工作的类
    • @ContextConfiguration(“classpath:appication-Collection.xml”) : 指定要加载的XML配置文件
    • @Test :写在测试方法上
  • ⑥ 元注解
    • @Target(ElementType.FIELD):定义注解的作用范围
    • @Retention(RetentionPolicy.RUNTIME):定义注解的生命周期(保留策略)
      自定义注解:必须带上面两个元注解

12.谈谈你对Spring AOP的理解?

  • ① 概念:是Aspect Oriented Programming的简写,翻译过来就是面向切面编程。
  • ② 核心思想:AOP把系统分为核心关注点和横切关注点两个部分,将应用程序中的业务逻辑同为其提供支持的通用服务进行分离。
    • 核心关注点:就是业务处理的主要流程(纵向的业务逻辑处理)
    • 横切关注点:就是出现在每个业务逻辑处理模块中的大量重复代码,比如说权限认证,日志,事务处理。
  • ③ AOP解决的问题:避免了出现大量的重复性代码,提高了代码的复用性。
  • ④ AOP底层使用的两种机制:JDK的动态代理和Java类库的CGLIB代理。
    • 如果我们类实现了接口,Spring底层实现AOP就会调用动态代理,否则就调用CGLIB代理。

13.XML方式实现AOP的通知有几种?

  • ① 前置通知 before
  • ② 环绕通知 around
  • ③ 后置通知 after-Returning
  • ④ 异常通知 after-Throwing
  • ⑤ 最终通知 after

14.注解实现AOP的过程?

       1.配置Spring XML文件
       	  开启自动代理 <aop:aspectj-autoproxy/> :声明自动为spring容器中那些配置@Aspect切面的bean创建代理,织入切面
          开启组件扫描 <context:component-scan base-package="com.wpq.Spring"/>
       2.创建切面类:给类上面添加@Aspect注解  
  	   3.切面类中配置切入点 :@Pointcut(value = "execution(* com.wpq.service.impl.*.*(..))")public void pointCut() {}
	   4.在切面类不同的方法中添加注解:
		  前置:@Before(value=“pointCut()”)
		  环绕: @Around(value=“pointCut()”)
		  后置: @AfterReturning(value=“pointCut()”)
		  异常: @AfterThrowing(value=“pointCut()”)
		  最终: @After(value=“pointCut()”)

15.更改多个切面类的执行顺序的方法有几种?

  • ① 默认按照类的首字母来执行,a-z/A-Z
  • ② 给切面类添加 @Order(v) 注解,v越小,优先级越高
  • ③ 切面类实现Order接口,重写getOrder()方法

16.Spring有哪些主要模块?

Spring框架至今已经集成了20多个模块。主要是核心容器、数据访问/集成、Web、AOP、工具、消息和测试模块。

17.Spring中的bean是线程安全的吗?

Spring容器中的Bean是否线程安全,容器本身并没有提供Bean的线程安全策略,因此可以说spring容器中的Bean本身不具备线程安全的特性,但是还是要结合具体的scope的Bean去研究。

18.Spring支持几种bean的作用域?

  • ① singleton 单例模式 (Scope默认):@Scope(value = “singleton”)
  • ② prototype 多例模式:每次获取Bean的时候会有一个新的实例
  • ③ request: request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效
  • ④ session:该作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效
  • ⑤ global session:该作用域类似于标准的HTTP Session作用域,不过它仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个 portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。如果你在web中使用global session作用域来标识bean,那么web会自动当成session类型来使用。

19.Spring JDBC的实现过程?

  • ① 添加spring-orm依赖包(SpringJDBC、mybatis、hibernate的必须依赖包)
<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-orm</artifactId>
   <version>${spring.version}</version>
</dependency>
  • ② 创建JdbcTemplate对象
1.封装一个xxxDao(UserDao)类,在类中直接通过自动装配注解注入
    @Autowired
    private JdbcTemplate jdbcTemplate; <先创建对象>
2.创建Spring XML配置文件 <把创建JdbcTemplate对象的权利交给Spring> 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
			     <!--1.开启组件扫描-->
				<context:component-scan base-package="com.wpq.dao"/>
                 <!--2.引入配置文件-->
				<context:property-placeholder location="xxx.properties" />
				 <!--3.创建连接池对象-->
				 <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
					 <property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
					 <property name="driverClass" value ="${jdbc.driverClass}"/>
					 <property name="user" value=" ${jdbc.user}"/>
					 <property name="password" value="${jdbc.password}"/>
				 </bean>	
                 <!--4.创建模板对象-->				 
				 <bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
				   <!--引用上面创建的连接池对象-->				
				   <property name="dataSource" ref="dataSource"/>
				 </bean> 
</beans>
  • ③ 使用JdbcTemplate对象
package com.wpq.dao.impl;

import com.wpq.dao.AccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class AccountDaoImpl implements AccountDao {

    @Autowired
    private JdbcTemplate template;

    @Override
    public void subMoney(Integer id, Double money) {
        System.out.println("账户:" + id + ",减钱了..." + money);
        String sql = "update tb_account set money=money - ? where id=?";
        template.update(sql, money, id);
    }

    @Override
    public void addMoney(Integer id, Double money) {
        System.out.println("账户:" + id + ",加钱了..." + money);
        String sql = "update tb_account set money=money + ? where id=?";
        template.update(sql, money, id);
    }
}

20.事务的概念是什么?

事务是一组原子性的SQL查询,或者说是一个独立的工作单位。(要么全部成功,要么全部失败)

21.事务的特性有几个?

  • ① 原子性(atomicity):指处于同一个事务中的多条SQL查询是不可分割的,要么全部提交成功,要么全部提交失败回滚。
  • ② 一致性(consistency):事务必须使数据库从一个一致性状态变换到另外一个一致性状态。比如转账,转账前两个账户余额之和为2k,转账之后也应该是2K。
  • ③ 隔离性(isolation):指多线程环境下,一个事务所做的修改在最终提交以前,对其它事务是不可见的。
  • ④ 持久性(durability):事务一旦提交,则其所做的修改就会永久保存到数据库中。

22.数据库操作时可能存在的问题有哪些?

  • ① 脏读:指一个线程中的事务读取到了另外一个线程中事务未提交的数据。
  • ② 不可重复读:指一个线程中的事务读取到了另外一个线程中事务提交的update的数据,读取到之前查询一次,读取到之后查询一次,两次查询结果不一样。
  • ③ 幻读:指的是当A事务在读取某个范围内的记录时,B事务又在该范围内插入了新的记录,当A事务再次读取该范围的记录时,会产生幻行(指一个线程中的事务读取到了另外一个线程中事务提交的insert数据)。

23.什么是事务的隔离级别?事务的隔离级别有几个?

概念: 指的是一个事务对数据的修改与另一个并发的事务的隔离程度。当多个事务同时访问相同数据时,如果没有采取必要的隔离机制,就可能发生脏读,不可重复读和幻读的问题。

  • ① READ UNCOMMITTED 未提交读(最低级别)
  • ② READ COMMITTED 提交读–>解决了脏读
  • ③ REPEATABLE READ 可重复读 (MySQL的默认) -->解决了脏读和不可重复读
  • ④ SERIALIZABLE 可串行化 (最高级别) -->解决了脏读,不可重复读和幻读

24.Spring中事务的传播行为有几种?

  • ① PROPAGATION_REQUIRED(默认) :表示当前方法必须运行在事务中
  • ② PROPAGATION_REQUIRED_NEW:表示当前方法必须运行在它自己的事务中
  • ③ PROPAGATION_SUPPORTS :表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行
  • ④ PROPAGATION_NOT_SUPPORTED: 表示该方法不应该运行在事务中
  • ⑤ PROPAGATION_NEVER: 表示当前方法不应该运行在事务上下文中
  • ⑥ PROPAGATION_NESTED: 表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行
  • ⑦ PROPAGATION_MANDATORY:表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常

25.Spring 声明式事务的实现?

  • ① 传统事务实现方案:利用JDBC通过手动编写事务相关代码来实现。
        try{
            beginTransaction();
            业务代码;
            commit();
        }catch (Exception e){
            rollback();
        }
  • ② Spring实现声明式事务的原理:AOP
  • ③ XML方式实现声明式事务
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
                 <!--开启组件扫描-->
				<context:component-scan base-package="com.wpq"/>
                 <!--引入配置文件-->
				<context:property-placeholder location="xxx.properties" />
				 <!--创建连接池对象-->
				 <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
					 <property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
					 <property name="driverClass" value ="${jdbc.driverClass}"/>
					 <property name="user" value=" ${jdbc.user}"/>
					 <property name="password" value="${jdbc.password}"/>
				 </bean>	
     1.配置一个事务管理器
		<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
					<!--将事务管理器,与我们上面定义的数据源绑定在一起.-->
					<property name="dataSource" ref="dataSource"/>
		</bean>
     2.配置一个事务切面类,配置事务规则
		<tx:advice id="txAdvice" transaction-manager="transactionManager">
					<tx:attributes>
							
							<!--给service层中,名称是transfer开头的所有的方法添加事务!-->
							<tx:method name="transfer**" isolation="REPEATABLE_READ" propagation="REQUIRED"/>
							
							<!--给service层中所有的增删改方法,添加事务-->
							<tx:method name="add**"/>
							<tx:method name="delete**"/>
							<tx:method name="update**"/>
							
							<!--对查询方法进行事务处理-->
							<tx:method name="select**" propagation="SUPPORTS" read-only="true"/>
					</tx:attributes>
		</tx:advice>  
					
     3.把目标类和切面类整合在一起
		<aop:congfig>
					
		     <!--事务添加在业务层,保证业务层的正确执行,
		     expression:切入点表达式,指定要添加事务功能的某个路径下的类中的方法-->
		     
			 <aop:pointcut id="pointCut" expression="execution(* com.wpq.service.impl.*.*(..))"/>
					
			<!--advice-ref:用来引用一个关于事务切面的增强通知方法-->
			<aop:advisor advice-ref="txAdvice" pointcut-ref="pointCut"/>
		</aop:config> 
    4.实现自己的service层业务代码
</beans>
  • 1.账户类
package com.wpq.domain;

/**
 * 1.账户类
 */
@Data
public class Account {

    private Integer from;//转账者
    private Integer to;//接收者
    private Double money;//金额
}
  • 2.数据访问类
package com.wpq.dao.impl;

import com.wpq.dao.AccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
/**
*2.数据访问类
*/
@Repository
public class AccountDaoImpl implements AccountDao {

    @Autowired
    private JdbcTemplate template;

    @Override
    public void subMoney(Integer id, Double money) {
        System.out.println("账户:" + id + ",减钱了..." + money);
        String sql = "update tb_account set money=money - ? where id=?";
        template.update(sql, money, id);
    }

    @Override
    public void addMoney(Integer id, Double money) {
        System.out.println("账户:" + id + ",加钱了..." + money);
        String sql = "update tb_account set money=money + ? where id=?";
        template.update(sql, money, id);
    }
}
  • 3.业务处理类
package com.wpq.service.impl;

import com.wpq.dao.AccountDao;
import com.wpq.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
*3.业务处理类
*/
@Service
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountDao accountDao;

    //转账业务最起码分为2步:从A账户减钱;在B账户加钱;
    //可以人为制造异常:int i = 10 / 0;来检验此方法是否具备事务功能
    @Override
    public void transfer(Integer from, Integer to, Double money) {
      
        System.out.println("service层...转账业务...");
        accountDao.subMoney(from, money);
        //int i = 10 / 0;
        accountDao.addMoney(to, money);
    }

}
  • 4.用户访问类
package com.wpq.web;

import com.wpq.domain.Account;
import com.wpq.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

/**
 * 4.用户访问类
 */
@Controller
public class AccountController {

    @Autowired
    private AccountService accountService;

    @RequestMapping("/trans")
    public void transfer(Account account) {
        System.out.println("web层...转账接口...");
        accountService.transfer(account.getFrom(), account.getTo(), account.getMoney());
    }
}
  • ④ 注解方式实现声明式事务
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
                 <!--开启组件扫描-->
				<context:component-scan base-package="com.wpq"/>
                 <!--引入配置文件-->
				<context:property-placeholder location="xxx.properties" />
				 <!--创建连接池对象-->
				 <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
					 <property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
					 <property name="driverClass" value ="${jdbc.driverClass}"/>
					 <property name="user" value=" ${jdbc.user}"/>
					 <property name="password" value="${jdbc.password}"/>
				 </bean>	       

1.XML中配置一个事务管理器
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
			<!--将事务管理器,与我们上面定义的数据源绑定在一起.-->
			<property name="dataSource" ref="dataSource"/>
	</bean>   			
2.XML中开启事务的注解功能
    <tx:annotation-driven/>			
3.在业务类或者业务方法上面添加注解
	@Transactional(isolation =Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED)
</beans>
package com.wpq.service.impl;

import com.wpq.dao.AccountDao;
import com.wpq.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
*3.业务处理类
*@Transactional注解写在类上方:表示给当前类中所有业务方法开启事务
*@Transactional注解写在类中的某个方法上:表示给当前业务方法开启事务
*/
@Service
@Transactional(isolation =Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED)
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountDao accountDao;

    //转账业务最起码分为2步:从A账户减钱;在B账户加钱;
    //可以人为制造异常:int i = 10 / 0;来检验此方法是否具备事务功能
    @Override
    //@Transactional(isolation =Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED)
    public void transfer(Integer from, Integer to, Double money) {
      
        System.out.println("service层...转账业务...");
        accountDao.subMoney(from, money);
        //int i = 10 / 0;
        accountDao.addMoney(to, money);
    }

}
# Spring 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×