JAVA后端面试《Spring》
- 2020 年 2 月 25 日
- 筆記
Spring
- Spring是什么?有什么好处?
- IOC是什么?有什么好处?简单过程?
- DI是什么?
- IOC和DI的关系?
- bean标签的属性有哪些?
- IOC创建对象有哪几种方式?
- Spring是如何实现IOC的?也就是如何创建对象的?
- Spring Bean的生命周期?
- 依赖注入DI的方式有几种?
- 注解实现IOC和DI的准备工作有哪些?
- 有哪些注解?分别表示什么含义?
- 谈谈你对Spring AOP的理解?
- XML方式实现AOP的通知有几种?
- 注解实现AOP的过程?
- 更改多个切面类的执行顺序的方法有几种?
- Spring有哪些主要模块?
- Spring中的bean是线程安全的吗?
- Spring支持几种bean的作用域?
- Spring JDBC的实现过程?
- 事务的概念是什么?
- 事务的特性有几个?
- 数据库操作时可能存在的问题有哪些?
- 什么是事务的隔离级别?事务的隔离级别有几个?
- Spring中事务的传播行为有几种?
- 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.*; /** * 集合类型赋值 */publicclass 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; } @Overridepublic 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("${age}")
实现步骤: 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; @Repositorypublicclass AccountDaoImpl implements AccountDao { @Autowiredprivate JdbcTemplate template; @Overridepublic 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); } @Overridepublic 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.账户类 */@Datapublicclass 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.数据访问类 */@Repositorypublicclass AccountDaoImpl implements AccountDao { @Autowiredprivate JdbcTemplate template; @Overridepublic 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); } @Overridepublic 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.业务处理类 */@Servicepublicclass AccountServiceImpl implements AccountService { @Autowiredprivate AccountDao accountDao; //转账业务最起码分为2步:从A账户减钱;在B账户加钱;//可以人为制造异常:int i = 10 / 0;来检验此方法是否具备事务功能@Overridepublic 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.用户访问类 */@Controllerpublicclass AccountController { @Autowiredprivate 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) publicclass AccountServiceImpl implements AccountService { @Autowiredprivate 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); } }
原文链接:
https://blog.csdn.net/weixin_43766298/article/details/104208049