1、创建Dao
public class DeptDao {
//注入IOC容器
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void save(){
String sqlString = "insert into t_dept (deptName) values('haha')";
jdbcTemplate.update(sqlString);
}
}
2、创建DaoService
public class DeptService {
private DeptDao deptDao;
public void setDeptDao(DeptDao deptDao) {
this.deptDao = deptDao;
}
public void save(){
deptDao.save();
int i = 1/0;//如果有事务回滚功能,那么上一行的deptDao.save();虽然执行了,但是数据库不会新增一条数据
deptDao.save();
}
}
3、创建实体对象
public class Dept {
private int deptId;
private String deptName;
public int getDeptId() {
return deptId;
}
public void setDeptId(int deptId) {
this.deptId = deptId;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
}
4、配置Bean.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:p="http://www.springframework.org/schema/p"
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. 数据源对象: C3P0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql:///TEST"></property>
<property name="user" value="root"></property>
<property name="password" value="123456"></property>
<property name="initialPoolSize" value="3"></property>
<property name="maxPoolSize" value="10"></property>
<property name="maxStatements" value="100"></property>
<property name="acquireIncrement" value="2"></property>
</bean>
<!-- 2、创建JdbcTemplate实例 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 3、创建Dao -->
<bean id="deptDao" class="trans.DeptDao">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<!-- 4、创建Service -->
<bean id="deptService" class="trans.DeptService">
<property name="deptDao" ref="deptDao"></property>
</bean>
<!-- #############5. Spring声明式事务管理配置############### -->
<!-- 5.1 配置事务管理器类 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 5.2 配置事务增强 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="*" read-only="false"/>
</tx:attributes>
</tx:advice>
<!-- 5.3 配置AOP -->
<aop:config>
<aop:pointcut expression="execution(* trans.DeptService.*())" id="pt"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
</aop:config>
</beans>
5、创建测试类
public class App {
@Test
public void testTransaction() throws Exception {
ApplicationContext aContext = new ClassPathXmlApplicationContext("trans/bean.xml");
DeptService service = (DeptService) aContext.getBean("deptService");
service.save();
}
}
6、测试结果:
数据库中没有新增一条Dept的数据。
注解配置其实类似:
bean.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:p="http://www.springframework.org/schema/p"
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. 数据源对象: C3P0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql:///TEST"></property>
<property name="user" value="root"></property>
<property name="password" value="123456"></property>
<property name="initialPoolSize" value="3"></property>
<property name="maxPoolSize" value="10"></property>
<property name="maxStatements" value="100"></property>
<property name="acquireIncrement" value="2"></property>
</bean>
<!-- 2、创建JdbcTemplate实例 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 事务管理类配置 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 开启注解扫描 -->
<context:component-scan base-package="trans_anno"></context:component-scan>
<!-- 注解方式实现事务: 指定注解方式实现事务 -->
<tx:annotation-driven transaction-manager="txManager"/>
</beans>
Dao:
@Repository
public class DeptDao {
//注入IOC容器
@Resource
private JdbcTemplate jdbcTemplate;
public void save(){
String sqlString = "insert into t_dept (deptName) values('haha')";
jdbcTemplate.update(sqlString);
}
}
Service:
@Service
public class DeptService {
@Resource
private DeptDao deptDao;
@Transactional
public void save(){
deptDao.save();
int i = 1/0;//如果有事务回滚功能,那么上一行的deptDao.save();虽然执行了,但是数据库不会新增一条数据
deptDao.save();
}
}
Dept.java 与XML配置保持一致,不需要添加任何注解。
编译运行后结果与XML配置运行结果一致。
事务的相关属性:
@Transactional(
readOnly = false, // 读写事务
timeout = -1, // 事务的超时时间不限制
noRollbackFor = ArithmeticException.class, // 遇到数学异常不回滚
isolation = Isolation.DEFAULT, // 事务的隔离级别,数据库的默认
propagation= Propagation.REQUIRED // 事务的传播行为
)
事务传播行为:
Propagation.REQUIRED
指定当前的方法必须在事务的环境下执行;
如果当前运行的方法,已经存在事务, 就会加入当前的事务;
Propagation.REQUIRED_NEW
指定当前的方法必须在事务的环境下执行;
如果当前运行的方法,已经存在事务: 事务会挂起; 会始终开启一个新的事务,执行完后; 刚才挂起的事务才继续运行。
Class Log{
Propagation.REQUIRED
insertLog();
}
Propagation.REQUIRED
Void saveDept(){
insertLog(); // 加入当前事务
.. 异常, 会回滚
saveDept();
}
ClassLog{
Propagation.REQUIRED_NEW
insertLog();
}
Propagation.REQUIRED
Void saveDept(){
insertLog(); // 始终开启事务
..异常, 日志不会回滚
saveDept();
}