09 Spring 事务管理(@Transactional)基本使用
2016-12-14 14:59
435 查看
转载请注明来源 赖赖的博客
事务管理在持久层(数据库)操作中是不可或缺的,其主要目的是为了保证操作的完整性。
而Spring提供了强大的声明式事务管理的方式,其实现原理是采用了AOP对方法进行增强,使用起来非常方便,再也不用自己去管理事务(TRANSACTION)
数据库
创建语句:
右键App.java
Run as
Java Application
运行结果
Exception in thread “main” java.lang.RuntimeException: lailai
数据库新增两条记录:
account表中新增一条
pocket表中新增一条
有两条
我们来具体看下
函数执行过程:
通过
Connection connection = DataSourceUtils.getConnection(dataSource);
执行插入
connection.createStatement().execute(“INSERT INTO account (username, password, name,create_time) VALUES(‘” + username + “’,’” + password + “’,’” + name + “’,’” + System.currentTimeMillis() + “’)”);
判断是否用户名为
if (username == “lailai”) {
throw new RuntimeException(“lailai”);
}
执行插入
connection.createStatement().execute(“INSERT INTO pocket (username,current_money) VALUES(‘” + username + “’,’” + 0 + “’)”);
那么很明显,在
理论上讲,在抛错之前的所有语句都应该被执行,也就是说,我们应该向数据库中插入了三行数据,两条
让我们看看
@Transactional 注解(spring的事务管理)
细心的读者可以发现,在
当执行
这里有几个隐含的条件非常重要:
数据库连接的获取一定要通过
只有将异常抛出才能产生回滚,如果使用
默认情况下只有
@Transactional(rollbackFor={Exception.class})
如果使用mysql数据库,请不要用 MyISAM引擎,因为不支持事务,请使用InnoDB引擎
说了这么多限制,那么到底应该如何在Spring中配置事务呢:
增加了两个配置:
配置TransactionManager
开启注解驱动
无需增加额外依赖! spring-context中自带!
导语
只要你肯再坚持一会儿,就会发现世界如此简单。事务管理在持久层(数据库)操作中是不可或缺的,其主要目的是为了保证操作的完整性。
而Spring提供了强大的声明式事务管理的方式,其实现原理是采用了AOP对方法进行增强,使用起来非常方便,再也不用自己去管理事务(TRANSACTION)
实例
项目工程目录结构和代码获取地址
获取地址(版本Log将会注明每一个版本对应的课程)
https://github.com/laiyijie/SpringLearning目录结构&数据库
工程目录结构数据库
创建语句:
CREATE TABLE account ( username varchar(45) NOT NULL, password varchar(45) NOT NULL, name varchar(45) NOT NULL, create_time bigint(20) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; ALTER TABLE account ADD PRIMARY KEY (username); CREATE TABLE `pocket` ( `username` varchar(45) NOT NULL, `current_money` int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; ALTER TABLE `pocket` ADD PRIMARY KEY (`username`);
运行工程
运行方式右键App.java
Run as
Java Application
运行结果
Exception in thread “main” java.lang.RuntimeException: lailai
数据库新增两条记录:
account表中新增一条
pocket表中新增一条
项目详解
App.java
package me.laiyijie.demo; import org.springframework.context.support.ClassPathXmlApplicationContext; import me.laiyijie.demo.service.UserService; public class App { public static void main(String[] args) throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("root-context.xml"); UserService service = context.getBean(UserService.class); service.createAccount("laiyijie", "123123", "lai"); service.createAccount("lailai", "123123", "lai"); context.close(); } }
有两条
createAccount语句,却只产生了一个账号!问题肯定出现在
createAccount方法中
我们来具体看下
UserService的实现类
UserServiceImpl.java
package me.laiyijie.demo.service; import java.sql.Connection; import org.apache.commons.dbcp.BasicDataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.datasource.DataSourceUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class UserServiceImpl implements UserService { @Autowired private BasicDataSource dataSource; @Transactional public void createAccount(String username, String password, String name) throws Exception { Connection connection = DataSourceUtils.getConnection(dataSource); connection.createStatement().execute("INSERT INTO account (username, password, name,create_time) VALUES('" + username + "','" + password + "','" + name + "','" + System.currentTimeMillis() + "')"); if (username == "lailai") { throw new RuntimeException("lailai"); } connection.createStatement() .execute("INSERT INTO pocket (username,current_money) VALUES('" + username + "','" + 0 + "')"); } }
函数执行过程:
通过
DataSourceUtils.getConnection从
dataSource中获取connection
Connection connection = DataSourceUtils.getConnection(dataSource);
执行插入
account表的insert语句
connection.createStatement().execute(“INSERT INTO account (username, password, name,create_time) VALUES(‘” + username + “’,’” + password + “’,’” + name + “’,’” + System.currentTimeMillis() + “’)”);
判断是否用户名为
lailai,是的话抛出
运行时错误
if (username == “lailai”) {
throw new RuntimeException(“lailai”);
}
执行插入
connection.createStatement().execute(“INSERT INTO pocket (username,current_money) VALUES(‘” + username + “’,’” + 0 + “’)”);
那么很明显,在
main函数中执行第二次
createAccount的过程中,抛出了错误,而抛出错误的时间是在执行完插入account表之后!
理论上讲,在抛错之前的所有语句都应该被执行,也就是说,我们应该向数据库中插入了三行数据,两条
account数据,一条
account数据和一条
让我们看看
lailai这条
account数据去哪儿了。
@Transactional 注解(spring的事务管理)
细心的读者可以发现,在
createAccount函数之前我们增加了一个注解
@Transactional,这个是Spring事务管理的声明,其寓意为:
当执行
createAccount的时候,将创建一个事务,函数执行成功,则正常提交,当函数抛出
RuntimeExeption的时候则回滚
这里有几个隐含的条件非常重要:
数据库连接的获取一定要通过
DataSourceUtils.getConnection来获取。每一个事务都是绑定在一个连接上的,如果还是通过
datasource.getConnection方法获取连接则有可能是获取到别的连接(由于连接池的存在)而
DataSourceUtils.getConnection获取的连接是当前事务的连接
只有将异常抛出才能产生回滚,如果使用
try catch处理了异常是不能回滚的
默认情况下只有
RuntimeException的抛出会产生回滚,如果需要自行定义可以回滚的异常,可以通过增加
RollbackFor属性:
@Transactional(rollbackFor={Exception.class})
如果使用mysql数据库,请不要用 MyISAM引擎,因为不支持事务,请使用InnoDB引擎
说了这么多限制,那么到底应该如何在Spring中配置事务呢:
root-context.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:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd 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-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd"> <bean id="mysqlDataSource" class="org.apache.commons.dbcp.BasicDataSource" p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://127.0.0.1:3306/myspring" p:username="test" p:password="o34rWayJPPHgudtL" /> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="mysqlDataSource" /> <tx:annotation-driven transaction-manager="transactionManager" /> <context:component-scan base-package="me.laiyijie.demo"></context:component-scan> </beans>
增加了两个配置:
配置TransactionManager
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="mysqlData a686 Source" />
开启注解驱动
<tx:annotation-driven transaction-manager="transactionManager" />
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>me.laiyijie</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <dependencies> <!-- https://mvnrepository.com/artifact/org.springframework/spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.2.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.3.2.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-dbcp/commons-dbcp --> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> </dependencies> </project>
无需增加额外依赖! spring-context中自带!
相关文章推荐
- 09 Spring 事务管理(@Transactional)基本使用
- 09 Spring 事务管理(@Transactional)基本使用
- 09 Spring 事务管理(@Transactional)基本使用
- 09 Spring 事务管理(@Transactional)基本使用
- 09 Spring 事务管理(@Transactional)基本使用
- 09 Spring 事务管理(@Transactional)基本使用
- 09 Spring 事务管理(@Transactional)基本使用
- 09 Spring 事务管理(@Transactional)基本使用
- 09 Spring 事务管理(@Transactional)基本使用
- 09 Spring 事务管理(@Transactional)基本使用
- Spring的基本使用:通过annotation和xml方式进行申明式事务管理
- 使用spring实现事务管理(@transactional)的遇到的两个异常:java.lang.noclassdeffounderror:org/objectweb.asm
- Spring 下事务管理-使用AOP @Transactional注解管理
- Spring 下事务管理-使用AOP @Transactional注解管理
- spring 事务管理 1(使用spring的JdbcTemplate访问数据库)
- spring 事务管理 1(使用spring的JdbcTemplate访问数据库)
- Spring @Transactional 声明式事务管理 getCurrentSession
- Spring整合hibernate的事务属性介绍以及声明式事务管理 (使用Annotation和xml)
- [spring,mysql] spring使用注解式事务声明(@Transactional)无法回滚 .
- Spring整合hibernate的事务属性介绍以及声明式事务管理 (使用Annotation和xml)