用Idea写转账的Spring事务
创建一个maven项目
将spring事务的依赖导入pom.xml
<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
这里导入的是tx(事务)和MySQL连接的依赖
可以在maven仓库里搜索自己需要的包及其版本号
创建相应的bean,dao(接口),daoImpl,service,bean-config.xml
创建相应的数据库txspring及user表
id为主键
配置bean-config.xml(相当于application.xml)
在tx-config.xml中引入tx(后面再使用),context的命名空间,编写数据源DataSource
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--组件扫描(注解扫描)-->
<context:component-scan base-package="com.txspring"</context:component-scan>
<bean id="dataresouce" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/txspring"></property>
<property name="username" value="root"></property>
<property name="password" value=""></property>
</bean>
<!-- JdbcTemplate对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 注入DataSource-->
<property name="dataSource" ref="dataresouce"></property>
</bean>
</beans>
编写User.java
public class User {
private Integer id;
private String name;
private Integer money;
public Integer getMoney() {
return money;
}
public void setMoney(Integer money) {
this.money = money;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
编写UserDao接口
只是为了认识事务,就只写了简单的账户余额增加或减少
public interface UserDao {
public void addmoney();
public void reducemoney();
}
编写UserDaoImpl.java
实现UserDao接口里的方法及调用JdbcTemplate
package com.txspring.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository //持久层的注解
public class UserDaoImpl implements UserDao{
//自动配置set方法
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void addmoney() {
String sql = "update user set money=money+? where name=?";
//100为money,Mary,Lucy必须存在于表中
jdbcTemplate.update(sql,100,"mary");
}
@Override
public void reducemoney() {
String sql = "update user set money=money-? where name=?";
jdbcTemplate.update(sql,100,"lucy");
}
}
编写UserService.java
service来实现业务逻辑
@Service//service层的注解
public class UserService {
@Autowired
private UserDao userDao;
public void manager(){
//lucy少100
userDao.reducemoney();
//Mary多100
userDao.addmoney();
}
}
测试一下这个简单的业务逻辑
public class test {
@Test
public void test(){
ApplicationContext ac = new ClassPathXmlApplicationContext("bean-config.xml");
UserService userService = ac.getBean("userService",UserService.class);
userService.manager();
}
}
如果现实这样就代表运行成功,数据库也会有相应显示
运行结果:
到这里我们所需要的简单转账功能搭建好啦
接下来引入事务
引入事务
如果在service层出现了一个异常,那service层业务可能会出错
我们来模拟一下service层出现错误时,编译能否成功,数据库有没有改变
@Service
public class UserService {
@Autowired
private UserDao userDao;
public void manager(){
//lucy少100
userDao.reducemoney();
//异常
int i = 10/0;
//Mary多100
userDao.addmoney();
}
运行结果:
如果出现异常,编译会出错,程序执行了 userDao.reducemoney()方法,导致数据库里Lucy的money减少了100而Mary没有增加。
此时我们就需要事务来保证业务逻辑不会因为异常而出错
在bean-config.xml中添加事务管理器
事务分为两种:编程式事务和声明式事务;
编程式事务需要在service层写复杂的逻辑,后面如果需要添加什么会很繁琐容易出错,所以推荐使用声明式事务
声明式事务有两种方式:1.基于xml配置;2.注解
因为用注解的方式比较简单,下面就使用了注解
<!--声明式事务管理 1.在spring配置文件中配置事务管理器;2.在spring配置文件中,引入命名空间、开启事务注解;3.在service类/方法上面面添加事务注解-->
<!-- 创建事务管理器-->
<bean id="tansactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入数据源-->
<property name="dataSource" ref="dataresouce"></property>
</bean>
<!-- 开启事务注解-->
<tx:annotation-driven transaction-manager="tansactionManager"></tx:annotation-driven>
在UserService.java里添加注解@Transactional
@Service
@Transactional //事务注解,可添加到类(这个类里所有的方法都添加事务)或方法(只是为这个方法添加注解)
public class UserService {
了解一下@Transactional的参数
- 1.propagation:事务传播行为:(对数据库表数据进行变化的操作)
- 2.ioslation:事务隔离级别
- 3.timeout:超时时间
- 4.readOnly:是否只读
- 5.rollbackFor:回滚
- 6.noRollbackFor:不回滚
添加了@Transactional注解再运行时,编译仍会报错,但是数据库里的内容不会改变,这就体现了事务的特性