前言:声明式事务的底层实现就是AOP,前面也写过不少关于aop的案例,这次来结合操作数据库来看看事务管理
事务相关包
首先需要导入之前哪些和aop相关的包
然后就是spring-tx-xxx.jar
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
然后在spring配置文件里加入tx的头部文件,因为spring事务管理是依赖tx命名空间的
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd"
配置连接池和数据源
我这用的是上篇文章用到的jdbcTemplate数据源
<!--引入外部*.properties文件-->
<context:property-placeholder location="classpath:jdbc.properties" ignore-unresolvable="true"/>
<context:component-scan base-package="com.jdbctemplete"/>
<!--配置阿里druid连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="clone">
<property name="driverClassName" value="${jdriver}"/>
<property name="url" value="${jurl}"/>
<property name="username" value="${jusername}"/>
<property name="password" value="${jpassword}"/>
</bean>
<!-- 配置jdbcTemplate数据源-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置spring事务管理-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 开启srping事务管理注解支持-->
<tx:annotation-driven transaction-manager="transactionManager"/>
编写基本的dao、entity、service、test类
UserDao
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public int updateUser(User user) {
String sql = "insert into user(uname, pwd, age) VALUES (?,?,?)";
return jdbcTemplate.update(sql, user.getUname(),user.getPwd(),user.getAge());
}
}
User
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
private static final long serialVersionUID = 760803936321762172L;
private Integer uid;
private String uname;
private String pwd;
private Integer age;
public User(String uname, String pwd, Integer age) {
this.uname = uname;
this.pwd = pwd;
this.age = age;
}
}
UserServiceImpl(未加事务)
@Service("userService")
public class UserServiceImpl{
@Autowired
private UserDao userDao;
/**
* 修改用户信息
*
* @param user 用户信息对象
* @return 成功行数
*/
public void updateUser(User user) {
int count = userDao.updateUser(user);
int count2 = userDao.updateUser(user);
System.out.println("1:" + count);
System.out.println("1:" + count2);
}
}
测试类
@ContextConfiguration(locations = "classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class Test01 {
@Autowired
UserService userService=new UserServiceImpl();
@Test
public void test01() {
User user=new User("wangba","wb123",35);
userService.updateUser(user);
}
}
用户表
结果
org.springframework.dao.DuplicateKeyException: PreparedStatementCallback; SQL [insert into user(uname, pwd, age) VALUES (?,?,?)]; Duplicate entry 'wangba' for key 'user_uname_uindex'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry 'wangba' for key 'user_uname_uindex'
我数据库设置了不可插入重复的用户名,我在业务层执行插入同一个user两次,必然会抛异常如果没加事务,因为插入的是数据库没有的用户名,第一次插入肯定会成功,到第二次才会出异常,来看看有没有插入成功的
结果很显然,没加入事务,即便出异常了第一次还是成功插入了,如果是转账的话,你把钱转给别人,中间出错了,你钱没了,别人也没收到。
现在我把数据库数据全部删除
然后我加上事务,看看情况怎么样
UserServiceImpl(加了事务)
/**
*@Transactional开启事务
*/
@Transactional
@Service("userService")
public class UserServiceImpl{
@Autowired
private UserDao userDao;
/**
* 修改用户信息
*
* @param user 用户信息对象
* @return 成功行数
*/
public void updateUser(User user) {
int count = userDao.updateUser(user);
int count2 = userDao.updateUser(user);
System.out.println("1:" + count);
System.out.println("1:" + count2);
}
}
结果
org.springframework.dao.DuplicateKeyException: PreparedStatementCallback; SQL [insert into user(uname, pwd, age) VALUES (?,?,?)]; Duplicate entry 'wangba' for key 'user_uname_uindex'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry 'wangba' for key 'user_uname_uindex
异常还是一样的,不能插入两天用户名相同的数据,既然我们开启了事务,出了异常,那么应该回滚了
ok没问题,数据库还是空的,证明事务生效了。