当前位置: 首页 > news >正文

Spring笔记(9):事务管理ACID

一、事务管理

一个数据库事务是一个被视为单一的工作单元操作序列。

事务管理有四个原则,被成为ACID

  • Atomicity 原子性—— 事务作为独立单元进行操作,整个序列是一体的,操作全都成功或失败。
  • Consistency 一致性—— 引用完整性的一致性,表中唯一的主键等。
  • Isolation 隔离性—— 每个事务同时处理时,事务之间不会干预
  • Durability 持久性 事务一旦完成,结果是不可逆的,不会因为故障而失效

那么一个关系型数据库将保证事务有这四个原则。

使用SQL发布到数据库中的事务简单视图如下:

  • 使用begin transaction命令开始事务
  • 使用SQL查询语句执行更新操作
  • 如果操作都成功,则提交操作,否则回滚操作

Spring 事务支持

  • Spring框架在不同底层事务管理API的顶部提供了一个抽象层。
  • Spring事务支持主要通过添加事务能力到POJO来提供EJB事务。
  • Spring支持编程式和声明式事务管理。
  • EJB需要一个应用程序服务器,但Spring事务管理可以不需要应用程序服务器。

全局事务与局部事务

  • 局部事务?

它是一个特定单一事务资源,例如一个JDBC连接。

若你的生产环境是集中的,该环境中的程序组件和资源位于一个位置,而事务管理只涉及到一个运行
单一机器中的本地数据管理器,则适用局部事务。

  • 全局事务?

它可以跨多个事务资源,如一个分布式系统中的事务。

若你的生产环境是分散的,所有资源分布在多个系统中,则需要局部事务和全局事务管理。
分布式或全局事务跨多个系统执行,它的执行需要全局事务管理系统和所有相关系统的局部数据管理人员之间的协调。

编程式与声明式事务管理

  • 编程式事务管理: 用编程的方式进行事务管理,灵活性较高,但维护性差。
  • 声明式事务管理: 从业务代码中分离事务管理,仅使用注释或XML配置来管理事务。

声明式事务管理比编程式事务管理更适合,它可以使用AOP方法进行模块化,Spring AOP框架也可以用来进行声明式事务管理。

Spring事务抽象

Spring事务管理的五大属性:隔离级别传播行为只读属性事务超时回滚规则

隔离级别

  • 默认: TransactionDefinition.ISOLATION_DEFAULT
  • 读取提交内容: TransactionDefinition.ISOLATION_READ_COMMITTED
    能阻止误读,可发生不可重复读和虚读。
  • 读取未提交内容: TransactionDefinition.ISOLATION_READ_UNCOMMITTED
    可以发生误读、不可重复读和虚读。
  • 可重读内容: TransactionDefinition.ISOLATION_REPEATABLE_READ
    表明能够阻止误读和不可重复读;可以发生虚读。
  • 可串行化: TransactionDefinition.ISOLATION_SERIALIZABLE
    表明能够阻止误读、不可重复读和虚读。

传播行为

  • 支持当前事务:
    TransactionDefinition.PROPAGATION_MANDATORY
  • 支持当前事务,在嵌套事务执行:
    TransactionDefinition.PROPAGATION_NESTED
  • 不支持当前事务:
    TransactionDefinition.PROPAGATION_NEVER
  • 不支持当前事务,总是执行非事务性: TransactionDefinition.PROPAGATION_NOT_SUPPORTED
  • 支持当前事务,若不存在则创建新事务:
    TransactionDefinition.PROPAGATION_REQUIRED
  • 创建新事务,将当前事务挂起:
    TransactionDefinition.PROPAGATION_REQUIRES_NEW
  • 支持当前事务,若不存在则执行非事务性:
    TransactionDefinition.PROPAGATION_SUPPORTS
  • 使用默认超时底层事务系统,若不支持超时则没有传播行为:
    TransactionDefinition.TIMEOUT_DEFAULT

事务抽象

Spring事务抽象由org.springframework.transaction.PlatformTransactionManager接口定义。

public interface PlatformTransactionManager{//根据传播行为,返回当前活动事务或创建新事务TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;//提交事务以及事务状态void commit(TransactionStatus status) throws TransactionException;//执行事务回滚void rollback(TransactionStatus status) throws TransactionException;
}

TransactionDefinition接口是Spring事务支持的核心接口,定义如下:

public interface TransactionDefinition{int getPropagationBehavior();	//获取传播行为int getIsolationLevel();	//获取隔离级别String getName(); //获取事务名称int getTimeout();	//获取事务超时时间boolean isReadOnly();	//获取只读属性
}

TransactionStatus接口为事务代码提供简单方法来控制事务执行和查询事务状态。

public interface TransactionStatus extends SavepointManager{boolean isNewTransaction();	//是否为新事务boolean hasSavepoint();	//该事务内部是否有一个保存点,也就是说,基于一个保存点已经创建了嵌套事务。void setRollbackOnly();	//该方法设置该事务为 rollback-only 标记。boolean isRollbackOnly();	//该事务是否已标记为 rollback-only。boolean isCompleted();	//事务是否已经提交或回滚。
}

二、编程式事务管理

我们尝试一下如何进行编程式事务管理。
步骤一:添加依赖包

  • jdbc.jar
  • mysql-connector.jar
  • transaction.jar

pom.xml

		<dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.3.23</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>5.3.24</version></dependency>

步骤二:创建POJO类

User.java

public class User{private Integer id;private String name;private Integer age;private Integer marks;private Integer year;private Integer sid;public User() {}public User(Integer id, String name, Integer age) {this.id = id;this.name = name;this.age = age;}public User(Integer id, String name, Integer age, Integer marks, Integer year, Integer sid) {this.id = id;this.name = name;this.age = age;this.marks = marks;this.year = year;this.sid = sid;}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;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public Integer getMarks() {return marks;}public void setMarks(Integer marks) {this.marks = marks;}public Integer getYear() {return year;}public void setYear(Integer year) {this.year = year;}public Integer getSid() {return sid;}public void setSid(Integer sid) {this.sid = sid;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", age=" + age +", marks=" + marks +", year=" + year +", sid=" + sid +'}';}
}

步骤三:创建dao层

UserDao.java

public interface UserDao {public void setDataSource(DataSource ds);public void create(String name,Integer age,Integer marks,Integer year);public List<User> listUsers();
}

步骤四:创建Mapper层

UserMapper.java

public class UserMapper implements RowMapper<User> {@Overridepublic User mapRow(ResultSet rs, int rowNum) throws SQLException {return new User(rs.getInt("id"),rs.getString("name"),rs.getInt("age"), rs.getInt("marks"),rs.getInt("year"),rs.getInt("sid"));}
}

步骤五:创建Template层

UserJdbcTemplate.java

public class UserJdbcTemplate implements UserDao {private DataSource dataSource;private JdbcTemplate jdbcTemplate;private PlatformTransactionManager platform;private String sql;public void setPlatform(PlatformTransactionManager platform) {this.platform = platform;}@Overridepublic void setDataSource(DataSource ds) {this.dataSource = ds;this.jdbcTemplate = new JdbcTemplate(dataSource);}@Overridepublic void create(String name, Integer age, Integer marks, Integer year) {TransactionDefinition definition = new DefaultTransactionDefinition();TransactionStatus status = platform.getTransaction(definition);try {sql = "insert into user (name,age) values(?,?)";jdbcTemplate.update(sql,name,age);sql = "select max(id) from user";int sid = jdbcTemplate.queryForInt(sql,null,Integer.class);sql = "insert into marks(sid,marks,year) values (?,?,?)";jdbcTemplate.update(sql,sid,marks,year);System.out.println("提交");platform.commit(status);}catch (DataAccessException e){System.out.println("Error in creating record,rolling back");platform.rollback(status);throw e;}return;}@Overridepublic List<User> listUsers() {sql = "select * from user u,marks m where u.id = m.sid";return jdbcTemplate.query(sql,new UserMapper());}}

步骤六:bean配置

jdbc.xml

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=false"/><property name="username" value="root"/><property name="password" value="123456"/></bean><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /></bean><bean id="userJDBCTemplate" class="org.example.Template.UserJdbcTemplate"><property name="dataSource" ref="dataSource" /><property name="platform" ref="transactionManager" /></bean>

输出结果

回滚事件:

------Records creation--------
Error in creating record,rolling back
Exception in thread "main" org.springframework.jdbc.BadSqlGrammarException: StatementCallback; bad SQL grammar [select max(id) form user]; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'user' at line 1at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:239)at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70)at org.springframework.jdbc.core.JdbcTemplate.translateException(JdbcTemplate.java:1541)at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:393)at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:465)at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:475)at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:508)at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:515)at org.example.Template.UserJdbcTemplate.create(UserJdbcTemplate.java:46)at org.example.Main.main(Main.java:26)
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'user' at line 1at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)at java.lang.reflect.Constructor.newInstance(Constructor.java:423)at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)at com.mysql.jdbc.Util.getInstance(Util.java:408)at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:944)at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3978)at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3914)at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2530)at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2683)at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2491)at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2449)at com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1381)at org.springframework.jdbc.core.JdbcTemplate$1QueryStatementCallback.doInStatement(JdbcTemplate.java:452)at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:381)... 6 more

三、声明式事务管理

我们来尝试一下声明式事务管理
这里展示与编程式事务管理的不同的地方。

1、Template类不再有PlatformTransactionManager参与,即正常的JDBC框架内容。
2、配置文件jdbc.xml,声明tx命名空间,aop命名空间,装配事务管理和面向切面配置

jdbc.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:tx="http://www.springframework.org/schema/tx"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.0.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-3.0.xsd"><!-- 初始化数据库连接池 --><bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/TEST"/><property name="username" value="root"/><property name="password" value="123456"/></bean>##AOP框架中实际调用的方法<tx:advice id="txAdvice"  transaction-manager="transactionManager">##目标<tx:attributes>##锚定方法<tx:method name="create"/></tx:attributes></tx:advice>##配置aop框架,设置切入点,加载advice<aop:config><aop:pointcut id="createOperation" expression="execution(* com.tutorialspoint.StudentJDBCTemplate.create(..))"/><aop:advisor advice-ref="txAdvice" pointcut-ref="createOperation"/></aop:config>##初始化事务管理器<bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource"  ref="dataSource" />    </bean>#初始化template<bean id="studentJDBCTemplate"  class="com.tutorialspoint.StudentJDBCTemplate"><property name="dataSource"  ref="dataSource" />  </bean></beans>
http://www.lryc.cn/news/34220.html

相关文章:

  • io流 知识点+代码实例
  • 【MySQL】P8 多表查询(2) - 连接查询 联合查询
  • QML动画(Animator)
  • Git 分支操作【解决分支冲突问题】
  • 盘点全球10大女性技术先驱
  • C++之dynamic_cast
  • JavaScript 箭头函数、函数参数
  • JavaScript_Object.keys() Object.values()
  • 扬帆优配|高送转+高分红+高增长潜力股揭秘
  • 基于transformer的多帧自监督深度估计 Multi-Frame Self-Supervised Depth with Transformers
  • 设计模式: 单例模式
  • idea编辑XML文件出现:Tag name expected报错
  • 第十三届蓝桥杯省赛C++ A组 爬树的甲壳虫(简单概率DP)
  • 手动集成Tencent SDK遇到的坑!!!
  • 三天吃透mybatis面试八股文
  • SpringBoot整合Quartz以及异步调用
  • Golang 中 Slice的分析与使用(含源码)
  • 瀑布开发与敏捷开发的区别,以及从瀑布转型敏捷项目管理的5大注意事项
  • “华为杯”研究生数学建模竞赛2007年-【华为杯】A题:建立食品卫生安全保障体系数学模型及改进模型的若干理论问题(附获奖论文)
  • 基于JavaWeb学生选课系统开发与设计(附源码资料)
  • centos7 oracle19c安装||新建用户|| ORA-01012: not logged on
  • 【算法设计-分治】递归与尾递归
  • HTML 编辑器
  • css盒模型详解
  • 函数模板(template关键字的应用)
  • 嵌入式学习笔记——使用寄存器编程操作GPIO
  • 图像的读取与保存
  • 【蓝桥杯集训·每日一题】AcWing 4074. 铁路与公路
  • 网络:TCP与UDP相关知识(详细)
  • 不好!有敌情,遭到XSS攻击【网络安全篇】