Spring事务(Transaction)
事务(Transaction)是基于关系型数据库(RDBMS)的企业应用的重要组成部分。在软件开发领域,事务扮演者十分重要的角色,用来确保应用程序数据的完整性和一致性。
事务具有 4 个特性:原子性、一致性、隔离性和持久性,简称为 ACID 特性。
原子性(Atomicity):一个事务是一个不可分割的工作单位,事务中包括的动作要么都做要么都不做。
一致性(Consistency):事务必须保证数据库从一个一致性状态变到另一个一致性状态,一致性和原子性是密切相关的。
隔离性(Isolation):一个事务的执行不能被其它事务干扰,即一个事务内部的操作及使用的数据对并发的其它事务是隔离的,并发执行的各个事务之间不能互相打扰。
持久性(Durability):持久性也称为永久性,指一个事务一旦提交,它对数据库中数据的改变就是永久性的,后面的其它操作和故障都不应该对其有任何影响。
事务允许我们将几个或一组操作组合成一个要么全部成功、要么全部失败的工作单元。如果事务中的所有的操作都执行成功,那自然万事大吉。但如果事务中的任何一个操作失败,那么事务中所有的操作都会被回滚,已经执行成功操作也会被完全清除干净,就好像什么事都没有发生一样。
在现实世界中,最常见的与事务相关的例子可能就是银行转账了。假设我们需要将 1000 元从 A 账户中转到 B 账户中,这个转账操作共涉及了以下两个操作。
从 A 账户中扣除 1000 元;
往 B 账户中存入 1000 元。
如果 A 账户成功地扣除了 1000 元,但向 B 账户存入时失败的话,那么我们将凭空损失 1000 元;如果 A 账户扣款时失败,但却成功地向 B 账户存入 1000 元的话,我们的账户就凭空多出了 1000 元,那么银行就会遭受损失。因此我们必须保证事务中的所有操作要么全部成功,要么全部失败,理解了这一点,我们也就抓住了事务的核心。
作为一款优秀的开源框架和应用平台,Spring 也对事务提供了很好的支持。Spring 借助 IoC 容器强大的配置能力,为事务提供了丰富的功能支持。
场景引入 :银行转账
如果中间出现了异常,就会导致上面的执行了,但是下面的没有执行
方法: 引入事务, 如果中间出现了异常,就进行事务回滚
使用@Transactional
User.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 package pers.dhx_.pojo;import org.springframework.stereotype.Component;@Component public class User { private int id; private String name; private double money; public User () {} public User (int id, String name, double money) { this .id = id; this .name = name; this .money = money; } public int getId () { return id; } public void setId (int id) { this .id = id; } public String getName () { return name; } public void setName (String name) { this .name = name; } public double getMoney () { return money; } public void setMoney (double money) { this .money = money; } }
UserDAO.java
1 2 3 4 5 6 package pers.dhx_.DAO;import pers.dhx_.pojo.User;public interface UserDAO { public void addMoney (User user,double money) ; public void removeMoney (User user,double money) ; }
UserDAOImpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package pers.dhx_.DAO.Impl;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.stereotype.Repository;import pers.dhx_.DAO.UserDAO;import pers.dhx_.pojo.User;@Repository public class UserDAOImpl implements UserDAO { @Autowired private JdbcTemplate jdbcTemplate; @Override public void addMoney (User user,double money ) { String sql="update t_account set money=money+? where username=?" ; jdbcTemplate.update(sql,money,user.getName()); } @Override public void removeMoney (User user,double money) { String sql="update t_account set money=money-? where username=?" ; jdbcTemplate.update(sql,money,user.getName()); } }
UserService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package pers.dhx_.service;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import pers.dhx_.DAO.Impl.UserDAOImpl;import pers.dhx_.DAO.UserDAO;import pers.dhx_.pojo.User;@Service public class UserService { @Autowired private UserDAO userDAO; public void transferMoney (User u1,User u2,double money) { userDAO.removeMoney(u1,money); userDAO.addMoney(u2,money); } public void setUserDAO (UserDAOImpl userDAO) { this .userDAO = userDAO; } }
bean1.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <?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 ="pers.dhx_" > </context:component-scan > <bean id ="dataSource" class ="com.alibaba.druid.pool.DruidDataSource" destroy-method ="close" > <property name ="url" value ="jdbc:mysql:///userdb" /> <property name ="username" value ="root" /> <property name ="password" value ="qwer" /> <property name ="driverClassName" value ="com.mysql.cj.jdbc.Driver" /> </bean > <bean id ="jdbcTemplate" class ="org.springframework.jdbc.core.JdbcTemplate" > <property name ="dataSource" ref ="dataSource" /> </bean > </beans >
Test
1 2 3 4 5 6 7 8 9 @Test public void AccountTest () { ApplicationContext applicationContext=new ClassPathXmlApplicationContext ("bean1.xml" ); User lucy=new User (1 ,"lucy" ,1000 ); User mary=new User (2 ,"mary" ,1000 ); UserService userService=applicationContext.getBean("userService" ,UserService.class); userService.transferMoney(lucy,mary,100 ); }
事务管理方式
Spring 支持以下 2 种事务管理方式。
事务管理方式
说明
编程式事务管理
编程式事务管理是通过编写代码实现 的事务管理。 这种方式能够在代码中精确地定义事务的边界,我们可以根据需求规定事务从哪里开始,到哪里结束。
声明式事务管理
Spring 声明式事务管理在底层采用了 AOP 技术,其最大的优点在于无须通过编程的方式管理事务,只需要在配置文件中 进行相关的规则声明,就可以将事务规则应用到业务逻辑中。
选择编程式事务还是声明式事务,很大程度上就是在控制权细粒度和易用性之间进行权衡。
编程式对事物控制的细粒度更高,我们能够精确的控制事务的边界,事务的开始和结束完全取决于我们的需求,但这种方式存在一个致命的缺点,那就是事务规则与业务代码耦合度高,难以维护,因此我们很少使用这种方式对事务进行管理。
声明式事务易用性更高,对业务代码没有侵入性,耦合度低,易于维护,因此这种方式也是我们最常用的事务管理方式。
Spring 的声明式事务管理主要通过以下 2 种方式实现:
事务操作
一、基于注解的声明式事务管理
在spring配置文件配置事务管理器
1 2 3 4 5 6 7 <bean id ="transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="dataSource" > </property > </bean > <tx:annotation-driven transaction-manager ="transactionManager" > </tx:annotation-driven >
在spring配置文件引入命名空间tx
1 2 3 4 5 6 7 8 9 10 <?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" >
在service类上面(获取service类里面方法上面添加事务注解)
@Transactional
可以加到类上面,也可以加到方法上面。
添加到类上面,相当于为这个类里面的所有方法添加事务
添加到方法上面,相当于为这个方法添加事务
1、事务传播行为
@Transactional(transactionManager = "REQUIRED")
@Transactional默认的传播行为是REQUIRED ,且一般情况下只用REQUIRED和REQUIRES_NEW,其他了解即可
REQUIRED :业务方法需要在一个事务中运行,如果方法运行时,已处在一个事务中,那么就加入该事务,否则自己创建一个新的事务。这是spring默认的传播行为。
NOT_SUPPORTED :声明方法不需要事务。如果方法没有关联到一个事务,容器不会为他开启事务,如果方法在一个事务中被调用,该事务会被挂起,调用结束后,原先的事务会恢复执行。
REQUIRESNEW :不管是否存在事务,该方法总会为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务挂起,新的事务被创建。
MANDATORY :该方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果在没有事务的环境下被调用,容器抛出例外。
SUPPORTS :该方法在某个事务范围内被调用,则方法成为该事务的一部分。如果方法在该事务范围外被调用,该方法就在没有事务的环境下执行。
NEVER :该方法绝对不能在事务范围内执行。如果在就抛异常。只有该方法没有关联到任何事务,才正常执行。
NESTED :如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效。
事务管理器
Spring 并不会直接管理事务,而是通过事务管理器对事务进行管理的。
在 Spring 中提供了一个 org.springframework.transaction.PlatformTransactionManager 接口,这个接口被称为 Spring 的事务管理器,其源码如下。
1 2 3 4 5 6 7 public interface PlatformTransactionManager extends TransactionManager { Transaction Status getTransaction (@Nullable TransactionDefinition definition) throws TransactionException; void commit (TransactionStatus status) throws TransactionException; void rollback (TransactionStatus status) throws TransactionException; }
该接口中各方法说明如下:
名称
说明
TransactionStatus getTransaction(TransactionDefinition definition)
用于获取事务的状态信息
void commit(TransactionStatus status)
用于提交事务
void rollback(TransactionStatus status)
用于回滚事务
Spring 为不同的持久化框架或平台(例如 JDBC、Hibernate、JPA 以及 JTA 等)提供了不同的 PlatformTransactionManager 接口实现,这些实现类被称为事务管理器实现。
实现类
说明
org.springframework.jdbc.datasource.DataSourceTransactionManager
使用 Spring JDBC 或 iBatis 进行持久化数据时使用。
org.springframework.orm.hibernate3.HibernateTransactionManager
使用 Hibernate 3.0 及以上版本进行持久化数据时使用。
org.springframework.orm.jpa.JpaTransactionManager
使用 JPA 进行持久化时使用。
org.springframework.jdo.JdoTransactionManager
当持久化机制是 Jdo 时使用。
org.springframework.transaction.jta.JtaTransactionManager
使用 JTA 来实现事务管理,在一个事务跨越多个不同的资源(即分布式事务)使用该实现。
这些事务管理器的使用方式十分简单,我们只要根据持久化框架(或平台)选用相应的事务管理器实现,即可实现对事物的管理,而不必关心实际事务实现到底是什么。
TransactionDefinition 接口
Spring 将 XML 配置中的事务信息封装到对象 TransactionDefinition 中,然后通过事务管理器的 getTransaction() 方法获得事务的状态(TransactionStatus),并对事务进行下一步的操作。
TransactionDefinition 接口提供了获取事务相关信息的方法,接口定义如下。
1 2 3 4 5 6 public interface TransactionDefinition { int getPropagationBehavior () ; int getIsolationLevel () ; String getName () ; int getTimeout () ; boolean isReadOnly () ;}
该接口中方法说明如下。
方法
说明
String getName()
获取事务的名称
int getIsolationLevel()
获取事务的隔离级别
int getPropagationBehavior()
获取事务的传播行为
int getTimeout()
获取事务的超时时间
boolean isReadOnly()
获取事务是否只读
2、事务的隔离级别
事务的隔离级别定义了一个事务可能受其他并发事务影响的程度。
在实际应用中,经常会出现多个事务同时对同一数据执行不同操作,来实现各自的任务的情况。此时就有可能导致==脏读、幻读以及不可重复读==等问题的出现。
在理想情况下,事务之间是完全隔离的,这自然不会出现上述问题。但完全的事务隔离会导致性能问题,而且并不是所有的应用都需要事务的完全隔离,因此有时应用程序在事务隔离上也有一定的灵活性。
Spring 中提供了以下隔离级别,我们可以根据自身的需求自行选择合适的隔离级别。
方法
说明
ISOLATION_DEFAULT
使用后端数据库默认的隔离级别
ISOLATION_READ_UNCOMMITTED
允许读取尚未提交的更改,可能导致脏读、幻读和不可重复读
ISOLATION_READ_COMMITTED
Oracle 默认级别,允许读取已提交的并发事务,防止脏读,可能出现幻读和不可重复读
ISOLATION_REPEATABLE_READ
MySQL 默认级别,多次读取相同字段的结果是一致的,防止脏读和不可重复读,可能出现幻读
ISOLATION_SERIALIZABLE
完全服从 ACID 的隔离级别,防止脏读、不可重复读和幻读
关于事务隔离级别、脏读、幻读、不可重复度等概念的详细介绍,请阅读《数据库事务隔离级别 》一节。
🎈4个级别
1.读未提交:==read uncommitted==
(最低的隔离级别)《没有提交就读到了》
什么是读未提交?
事务A可以读取到事务B未提交的数据。
这种隔离级别存在的问题就是:脏读现象!(Dirty Read)
我们称读到了脏数据。
这种隔离级别一般都是理论上的,大多数的数据库隔离级别都是二档起步!
2.读已提交:==read committed==
《提交之后才能读到》
3.可重复读:==repeatable read== -->MySQL默认
提交之后也读不到,永远读取的都是刚开启事务时的数据
什么是可重复读取?
事务A开启之后,不管是多久,每一次在事务A中读取到的数据
都是一致的。即使事务B将数据已经修改,并且提交了,事务A
读取到的数据还是没有发生改变,这就是可重复读。
可重复读解决了什么问题?
解决了不可重复读取数据。
可重复读存在的问题是什么?
可以会出现幻影读。
每一次读取到的数据都是幻象。不够真实!
早晨9点开始开启了事务,只要事务不结束,到晚上9点,读到的数据还是那样!
读到的是假象。不够绝对的真实。
mysql中默认的事务隔离级别就是==repeatable read==
4.序列化/串行化:==serializable==
(最高的隔离级别)
最高隔离级别,效率最低。解决了所有的问题。
这种隔离级别表示事务排队,不能并发!
synchronized ,线程同步(事务同步)
每一次读取到的数据都是最真实的,并且效率是最低的。
会卡住没有反应,直到另一个事务 commit
查看隔离级别:
MySQL 8 之前:SELECT @@tx_isolation
MySQL 8 之后:select @@transaction_isolation;
1 2 3 4 5 +----------------------+ | @@transaction_isolation | +----------------------+ | REPEATABLE-READ | +----------------------+
MySQL默认的隔离级别为repeatable read
隔离: isolation
修改事务隔离级别
1 2 3 4 5 6 7 set global transaction isolation level read uncommitted 设置 全局 事务 隔离 等级 读 未提交 set global transaction isolation level read committed set global transaction isolation level repeatable read set global transaction isolation level serializable
3、事务超时
设置事务超时时间
1 @Transactional (propagation = Propagation.REQUIRED,timeout=30 )
Spring事务超时 = 事务开始时到最后一个Statement创建时时间 + 最后一个Statement的执行时超时时间(即其queryTimeout)。
设置了超时时间,如DataSourceTransactionManager首先开启事物会调用其doBegin方法:
1 2 3 4 int timeout = determineTimeout(definition); if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) { txObject.getConnectionHolder().setTimeoutInSeconds(timeout); }
其中determineTimeout用来获取我们设置的事务超时时间;然后设置到ConnectionHolder对象上(其是ResourceHolder子类),接着ResourceHolderSupport的setTimeoutInSeconds实现:
4、事务的只读readonly
readOnly=true只读,不能更新,删除
1 @Transactional (propagation = Propagation.REQUIRED,readOnly=true )
注意:一次执行多次查询来统计某些信息,这时为了保证数据整体的一致性,要用只读事务。
由于只读事务不存在数据的修改,因此数据库将会为只读事务提供一些优化手段,例如Oracle对于只读事务,不启动回滚段,不记录回滚log。
1、在JDBC中,指定只读事务的办法为: connection.setReadOnly(true);
2、在Hibernate中,指定只读事务的办法为: session.setFlushMode(FlushMode.NEVER);
此时,Hibernate也会为只读事务提供Session方面的一些优化手段
3、在Spring的Hibernate封装中,指定只读事务的办法为: bean配置文件中,prop属性增加“readOnly”,或者用注解方式@Transactional(readOnly=true)
【 if the transaction is marked as read-only, Spring will set the Hibernate Session’s flush mode to FLUSH_NEVER, and will set the JDBC transaction to read-only】也就是说在Spring中设置只读事务是利用上面两种方式。
1 @Transactional(readOnly = false,timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
TransactionStatus 接口
TransactionStatus 接口提供了一些简单的方法,来控制事务的执行、查询事务的状态,接口定义如下。
1 2 3 4 5 6 7 public interface TransactionStatus extends SavepointManager { boolean isNewTransaction () ; boolean hasSavepoint () ; void setRollbackOnly () ; boolean isRollbackOnly () ; boolean isCompleted () ; }
该接口中各方法说明如下。
名称
说明
boolean hasSavepoint()
获取是否存在保存点
boolean isCompleted()
获取事务是否完成
boolean isNewTransaction()
获取是否是新事务
boolean isRollbackOnly()
获取事务是否回滚
void setRollbackOnly()
设置事务回滚
二、基于xml文件的声明式事务管理配置
1️⃣配置事务管理器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <?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.atguigu" > </context:component-scan > <bean id ="dataSource" class ="com.alibaba.druid.pool.DruidDataSource" destroy-method ="close" > <property name ="url" value ="jdbc:mysql:///user_db" /> <property name ="username" value ="root" /> <property name ="password" value ="root" /> <property name ="driverClassName" value ="com.mysql.jdbc.Driver" /> </bean > <bean id ="jdbcTemplate" class ="org.springframework.jdbc.core.JdbcTemplate" > <property name ="dataSource" ref ="dataSource" > </property > </bean > <bean id ="transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="dataSource" > </property > </bean > </beans >
2️⃣配置通知
propagation :传播;扩展;宣传;培养 —> 事务传播
pointcut : 切入点
advisor : 顾问;提供意见者 — > 通知
1 2 3 4 5 6 7 8 9 <tx:advice id ="txadvice" > <tx:attributes > <tx:method name ="accountMoney" propagation ="REQUIRED" /> </tx:attributes > </tx:advice >
3️⃣配置切入点和切面
1 2 3 4 5 6 7 <aop:config > <aop:pointcut id ="pt" expression ="execution(* com.atguigu.spring5.service.UserService.*(..))" /> <aop:advisor advice-ref ="txadvice" pointcut-ref ="pt" /> </aop:config >
总览
bean.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 <?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.atguigu" ></context:component-scan> <!-- 数据库连接池 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close" > <property name="url" value="jdbc:mysql:///user_db" /> <property name="username" value="root" /> <property name="password" value="root" /> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> </bean> <!-- JdbcTemplate对象 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" > <!--注入dataSource--> <property name="dataSource" ref="dataSource" ></property> </bean> <!--1 创建事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <!--注入数据源--> <property name="dataSource" ref="dataSource" ></property> </bean> <!--2 配置通知--> <tx:advice id="txadvice" > <!--配置事务参数--> <tx:attributes> <!--指定哪种规则的方法上面添加事务--> <tx:method name="accountMoney" propagation="REQUIRED" /> <!--<tx:method name="account*" />--> </tx:attributes> </tx:advice> <!--3 配置切入点和切面--> <aop:config> <!--配置切入点--> <aop:pointcut id="pt" expression="execution(* com.atguigu.spring5.service.UserService.*(..))" /> <!--配置切面--> <aop:advisor advice-ref="txadvice" pointcut-ref="pt" /> </aop:config> </beans>
三、完全注解开发
依然是创建配置类,使用配置类替代xml文件
@Configuration
ctrl+ enter 下方添加行 ctrl+shift+BackSpace 下方删除行
使用到的注解
用处
@Configuration
表明这个类是一个配置类
@ComponentScan(basePackages = “com.atguigu”)
组件扫描
@EnableTransactionManagement
开启事务
@Bean
告诉方法,产生一个Bean对象,这个Bean对象交给Spring管理。产生这个Bean对象的方法Spring只会调用一次,随后这个Spring将会将这个Bean对象放在自己的IOC容器中。
TxConfig.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 package com.atguigu.spring5.config;import com.alibaba.druid.pool.DruidDataSource;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.jdbc.datasource.DataSourceTransactionManager;import org.springframework.transaction.annotation.EnableTransactionManagement;import javax.sql.DataSource;@Configuration @ComponentScan(basePackages = "com.atguigu") @EnableTransactionManagement public class TxConfig { @Bean public DruidDataSource getDruidDataSource () { DruidDataSource dataSource = new DruidDataSource (); dataSource.setDriverClassName("com.mysql.jdbc.Driver" ); dataSource.setUrl("jdbc:mysql:///user_db" ); dataSource.setUsername("root" ); dataSource.setPassword("root" ); return dataSource; } @Bean public JdbcTemplate getJdbcTemplate (DataSource dataSource) { JdbcTemplate jdbcTemplate = new JdbcTemplate (); jdbcTemplate.setDataSource(dataSource); return jdbcTemplate; } }
用到的注解
使用到的注解
作用
@Configuration
表明这个类是一个配置类
@ComponentScan(basePackages = “com.atguigu”)
开启组件扫描
@EnableTransactionManagement
开启事务
@Bean
告诉方法,产生一个Bean对象,这个Bean对象交给Spring管理。产生这个Bean对象的方法Spring只会调用一次,随后这个Spring将会将这个Bean对象放在自己的IOC容器中。