目标:熟悉事务管理的核心接口,能够说出它的3个核心接口及内容
spring-tx-5.2.8.RELEAS依赖包的3个接口
1.PlatformTransactionManager接口
PlatformTransactionManager接口主要用于管理事务,该接口中提供了三个管理事物的方法。
在实际应用中,Spring事务管理实际是由具体的持久化技术完成的,而
PlatformTransactionManager接口只提供统一的抽象方法。为了应对不同持久化技术的差异性,Spring为他们提供了具体的实现类,例如,Spring为Spring JDBC和MyBatis等依赖于DataSource的持久化技术提供了实现类DataSourceTransactionManager,如此以来,Spring JDBC或MyBatis等持久化技术的事务管理可以由DataSourceTransactionManager类实现,而且Spring 可以通过PlatformTransactionManager接口对这些实现类进行统一管理。
2.TransactionDefinition接口
TransactionDefinition接口中定义了事务描述相关的常量,其中包括了事务的隔离级别、事务的传播行为、事务的超时时间和是否为只读事务。
事务的隔离级别
事务的传播行为
事务的传播行为是指处于不同事务中的方法在相互调用时,方法执行期间,事务的维护情况。例如,当一个事务的方法B调用另一个事务的方法A时,可以规定A方法继续在B方法所属的现有事务中运行,也可以规定A方法开启一个新事务,在新事务中运行,B方法所属的现有事务先挂起,等A方法的新事务执行完毕后再恢复。
TransactionDefinition接口中定义的7种事务传播行为
事务的超时时间
事务的超时时间是指事务执行的时间界限,超过这个时间界限,事务将会回滚。TransactionDefinition接口提供了TIMEOUT_DEFAULT常量定义事务的超时时间。
是否为只读事务
当事务为只读时,该事务不修改任何数据,只读事务有助于提升性能,如果在只读事务中修改数据,会引发异常。TransactionDefinition接口中除了提供事务的隔离级别、事务的传播行为、事务的超时时间和是否为只读事务的常量外,还提供了一系列方法来获取事务的属性。
TransactionDefinition接口常用方法
3.TransactionStatus接口
TransactionStatus接口主要用于界定事务的状态,通常情况下,编程式事务中使用该接口较多。TransactionStatus接口提供了一系列返回事务状态信息的方法,具体如下。
熟悉事务管理的方式,能够说出Spring事务管理的两种方式分别是什么
Spring中的事务管理分为两种方式,一种是传统的编程式事务管理,另一种是声明式事务管理。
编写式事务管理有点落后,一般使用第二种,声明式事务管理
实现XML方式的声明式事务
没有配置事务具体实现代码:
这是一开始表中的数据:
现在模拟zhangsan给lisi转账100元
pom.xml
4.0.0 org.example _20230319 1.0-SNAPSHOT 8 8 UTF-8 org.springframework spring-context 5.2.3.RELEASE org.springframework spring-beans 5.2.3.RELEASE mysql mysql-connector-java 5.1.47 org.springframework spring-jdbc 5.3.6 org.springframework spring-tx 5.3.6 org.springframework spring-aspects 4.2.4.RELEASE
AccountDaoImpl:
package cn.hdc.dao.impl;import cn.hdc.dao.AccountDao;
import cn.hdc.model.Account;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;import java.util.List;public class AccountDaoImpl implements AccountDao {private JdbcTemplate jdbcTemplate;public JdbcTemplate getJdbcTemplate() {return jdbcTemplate;}public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}@Overridepublic Integer addAccount(Account account) {String sql = "insert into account(username,balance) values(?,?)";Object[] params = new Object[]{account.getUsername(), account.getBalance()};jdbcTemplate.update(sql, params);return jdbcTemplate.update(sql, params);}@Overridepublic Integer deleteAccount(Integer id) {String sql = "delete from account where id = ?";return jdbcTemplate.update(sql, id);}@Overridepublic Integer updateAccount(Account account) {String sql = "update account set username=?,balance=? where id=?";Object[] params = new Object[]{account.getUsername(), account.getBalance(), account.getId()};return jdbcTemplate.update(sql, params);}@Overridepublic Account findAccountById(Integer id) {String sql = "select * from account where id = ?";RowMapper accountRowMapper = new BeanPropertyRowMapper<>(Account.class);Account account = jdbcTemplate.queryForObject(sql, accountRowMapper, id);return jdbcTemplate.queryForObject(sql, accountRowMapper, id);}@Overridepublic List findAll() {String sql = "select * from account";RowMapper accountRowMapper = new BeanPropertyRowMapper<>(Account.class);List list = jdbcTemplate.query(sql, accountRowMapper);return list;}//模拟转账操作@Overridepublic void transfer(String outUser, String inUser, Double money) {//收款jdbcTemplate.update("update account set balance = balance + ? where username = ?", money, inUser);//模拟异常int i = 10 / 0;//付款jdbcTemplate.update("update account set balance = balance - ? where username = ?", money, outUser);}
}
AccountDao接口:
package cn.hdc.dao;import cn.hdc.model.Account;import java.util.List;public interface AccountDao {public Integer addAccount(Account account);public Integer deleteAccount(Integer id);public Integer updateAccount(Account account);public Account findAccountById(Integer id);public List findAll();public void transfer(String outUser, String inUser, Double money);
}
Account实体类:
package cn.hdc.model;public class Account {private Integer id;private String username;private Double balance;@Overridepublic String toString() {return "Account{" +"id=" + id +", username='" + username + '\'' +", balance=" + balance +'}';}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public Double getBalance() {return balance;}public void setBalance(Double balance) {this.balance = balance;}
}
测试类:
import cn.hdc.dao.AccountDao;
import cn.hdc.dao.impl.AccountDaoImpl;
import cn.hdc.model.Account;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;import java.util.List;public class APP {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");JdbcTemplate jdbcTemplate = (JdbcTemplate) context.getBean("jdbcTemplate");AccountDao accountDao = (AccountDao) context.getBean("accountDao");accountDao.transfer("zhangsan", "lisi", 100.0);// List list = accountDao.findAll();
// list.forEach(account -> {
// System.out.println(account);
// });// Account account = accountDao.findAccountById(1);
// System.out.println(account);// Integer ret = accountDao.deleteAccount(2);
// if (ret > 0) {
// System.out.println("删除成功!");
// } else {
// System.out.println("删除失败!");
// }
// Account account1 = new Account();
// account1.setId(2);
// account1.setUsername("zhangsan");
// account1.setBalance(5000.02153);
// Integer ret = accountDao.updateAccount(account1);
// if (ret > 0) {
// System.out.println("修改成功!");
// } else {
// System.out.println("修改失败!");
// }// Account account = new Account();
// account.setUsername("tom");
// account.setBalance(1000.011);
// Integer ret = accountDao.addAccount(account);
// if (ret > 0) {
// System.out.println("插入成功!");
// } else {
// System.out.println("插入失败!");
// }// jdbcTemplate.execute("create table account" +
// "(" +
// " id int primary key auto_increment," +
// " username varchar(50)," +
// " balance double" +
// ");");
// System.out.println("account表创建成功!");// UserDaoImpl userDao = (UserDaoImpl) context.getBean("userDao");// System.out.println(userDao.getJdbcTemplate());}
}
运行结果:
看一下表数据:
张三的钱没扣!
接下来我们使用事务
具体实现代码:
现在还原一下表
pom.xml
4.0.0 org.example _20230319 1.0-SNAPSHOT 8 8 UTF-8 org.springframework spring-context 5.2.3.RELEASE org.springframework spring-beans 5.2.3.RELEASE mysql mysql-connector-java 5.1.47 org.springframework spring-jdbc 5.3.6 org.springframework spring-tx 5.3.6 org.springframework spring-aspects 4.2.4.RELEASE org.aspectj aspectjweaver 1.9.6 aopalliance aopalliance 1.0
AccountDao接口:
package cn.hdc.dao;import cn.hdc.model.Account;import java.util.List;public interface AccountDao {public Integer addAccount(Account account);public Integer deleteAccount(Integer id);public Integer updateAccount(Account account);public Account findAccountById(Integer id);public List findAll();public void transfer(String outUser, String inUser, Double money);
}
AccountDaoImpl
package cn.hdc.dao.impl;import cn.hdc.dao.AccountDao;
import cn.hdc.model.Account;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;import java.util.List;public class AccountDaoImpl implements AccountDao {private JdbcTemplate jdbcTemplate;public JdbcTemplate getJdbcTemplate() {return jdbcTemplate;}public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}@Overridepublic Integer addAccount(Account account) {String sql = "insert into account(username,balance) values(?,?)";Object[] params = new Object[]{account.getUsername(), account.getBalance()};jdbcTemplate.update(sql, params);return jdbcTemplate.update(sql, params);}@Overridepublic Integer deleteAccount(Integer id) {String sql = "delete from account where id = ?";return jdbcTemplate.update(sql, id);}@Overridepublic Integer updateAccount(Account account) {String sql = "update account set username=?,balance=? where id=?";Object[] params = new Object[]{account.getUsername(), account.getBalance(), account.getId()};return jdbcTemplate.update(sql, params);}@Overridepublic Account findAccountById(Integer id) {String sql = "select * from account where id = ?";RowMapper accountRowMapper = new BeanPropertyRowMapper<>(Account.class);Account account = jdbcTemplate.queryForObject(sql, accountRowMapper, id);return jdbcTemplate.queryForObject(sql, accountRowMapper, id);}@Overridepublic List findAll() {String sql = "select * from account";RowMapper accountRowMapper = new BeanPropertyRowMapper<>(Account.class);List list = jdbcTemplate.query(sql, accountRowMapper);return list;}//模拟转账操作@Overridepublic void transfer(String outUser, String inUser, Double money) {//收款jdbcTemplate.update("update account set balance = balance + ? where username = ?", money, inUser);//模拟异常int i = 10 / 0;//付款jdbcTemplate.update("update account set balance = balance - ? where username = ?", money, outUser);}
}
Account实体类:
package cn.hdc.model;public class Account {private Integer id;private String username;private Double balance;@Overridepublic String toString() {return "Account{" +"id=" + id +", username='" + username + '\'' +", balance=" + balance +'}';}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public Double getBalance() {return balance;}public void setBalance(Double balance) {this.balance = balance;}
}
applicationContext.xml
测试类:
import cn.hdc.dao.AccountDao;
import cn.hdc.dao.impl.AccountDaoImpl;
import cn.hdc.model.Account;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;import java.util.List;public class APP {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");JdbcTemplate jdbcTemplate = (JdbcTemplate) context.getBean("jdbcTemplate");AccountDao accountDao = (AccountDao) context.getBean("accountDao");accountDao.transfer("zhangsan", "lisi", 100.0);// List list = accountDao.findAll();
// list.forEach(account -> {
// System.out.println(account);
// });// Account account = accountDao.findAccountById(1);
// System.out.println(account);// Integer ret = accountDao.deleteAccount(2);
// if (ret > 0) {
// System.out.println("删除成功!");
// } else {
// System.out.println("删除失败!");
// }
// Account account1 = new Account();
// account1.setId(2);
// account1.setUsername("zhangsan");
// account1.setBalance(5000.02153);
// Integer ret = accountDao.updateAccount(account1);
// if (ret > 0) {
// System.out.println("修改成功!");
// } else {
// System.out.println("修改失败!");
// }// Account account = new Account();
// account.setUsername("tom");
// account.setBalance(1000.011);
// Integer ret = accountDao.addAccount(account);
// if (ret > 0) {
// System.out.println("插入成功!");
// } else {
// System.out.println("插入失败!");
// }// jdbcTemplate.execute("create table account" +
// "(" +
// " id int primary key auto_increment," +
// " username varchar(50)," +
// " balance double" +
// ");");
// System.out.println("account表创建成功!");// UserDaoImpl userDao = (UserDaoImpl) context.getBean("userDao");// System.out.println(userDao.getJdbcTemplate());}
}
运行结果:
表中数据没有变化,事务发生了回滚。
基于注解方式的声明式事务
@Transactional的属性
AccountDaoImpl在原来的基础上加上注解
applicationContext.xml
运行结果:
表中数据没有发生改变,事务生效