十四冶建设集团技工学校网站,免费制作企业贺卡,深圳龙华网站建设公司,门户网站综合型门户说到事务#xff0c;我们第一影响应该是数据库管理系统的一个重要概念。
事务#xff08;Transaction#xff09;是数据库管理系统#xff08;DBMS#xff09;中的一个概念#xff0c;用于管理对数据库的一组操作#xff0c;这些操作要么全部成功执行#xff0c;要么全…说到事务我们第一影响应该是数据库管理系统的一个重要概念。
事务Transaction是数据库管理系统DBMS中的一个概念用于管理对数据库的一组操作这些操作要么全部成功执行要么全部回滚撤销。
事务通常由一系列数据库操作组成例如插入、更新、删除等。这些操作被视为一个逻辑上的单元要么全部执行成功要么全部不执行。事务具有以下四个特性通常被称为 ACID 特性
原子性Atomicity事务被视为一个不可分割的原子操作要么全部执行成功要么全部回滚。如果事务中的任何一个操作失败整个事务将被回滚到初始状态数据库不会受到部分操作的影响。一致性Consistency事务在执行前和执行后数据库的完整性约束没有被破坏。这意味着事务必须确保数据库从一个一致的状态转换到另一个一致的状态。隔离性Isolation并发执行的多个事务之间应该相互隔离每个事务的操作应该与其他事务的操作相互独立。隔离性确保了每个事务在并发执行时不会相互干扰避免了数据的不一致性。持久性Durability一旦事务提交成功其所做的修改将永久保存在数据库中即使系统发生故障或重启修改的数据也不会丢失。
事务的使用可以确保数据库操作的一致性和可靠性尤其在并发访问数据库的环境中事务的隔离性能够避免数据冲突和并发问题。
那么我们在Spring Boot中如果实现对简单事务的处理呢
那就随我一同来通过Spring Boot来简单实现一个事务吧 引入相关依赖 dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-jpa/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactId/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdscopeprovided/scope/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependencies在Spring Boot的相关配置文件中配置数据库
spring.datasource.urljdbc:mysql://localhost:3306/test?useUnicodetruecharacterEncodingutf-8useSSLtrueserverTimezoneUTC
spring.datasource.primary.usernameroot
spring.datasource.usernameroot
spring.datasource.password123456
spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driverspring.jpa.database-platformorg.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-autocreateEntity
//Data
//NoArgsConstructor
public class User {IdGeneratedValueprivate Long id;private String name;Max(50)private Integer age;public User(String name, Integer age) {this.name name;this.age age;}public Long getId() {return id;}public void setId(Long 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 User() {}
}创建一个承载SQL的接口
public interface UserRepository extends JpaRepositoryUser, Long {User findByName(String name);User findByNameAndAge(String name, Integer age);Query(from User u where u.name:name)User findUser(Param(name) String name);}最后创建一个测试类
Slf4j
RunWith(SpringRunner.class)
SpringBootTest
public class ApplicationTests {Autowiredprivate UserRepository userRepository;Test//Transactional //这个注解先不加执行再一次执行的时候加然后看结果。public void test() throws Exception {// 创建10条记录userRepository.save(new User(AAA, 10));userRepository.save(new User(BBB, 20));userRepository.save(new User(CCC, 30));userRepository.save(new User(DDD, 40));userRepository.save(new User(EEE, 50));userRepository.save(new User(FFF, 60));userRepository.save(new User(GGG, 70));userRepository.save(new User(HHH, 80));userRepository.save(new User(III, 90));userRepository.save(new User(JJJ, 100));// 测试findAll, 查询所有记录Assert.assertEquals(10, userRepository.findAll().size());// 测试findByName, 查询姓名为FFF的UserAssert.assertEquals(60, userRepository.findByName(FFF).getAge().longValue());// 测试findUser, 查询姓名为FFF的UserAssert.assertEquals(60, userRepository.findUser(FFF).getAge().longValue());// 测试findByNameAndAge, 查询姓名为FFF并且年龄为60的UserAssert.assertEquals(FFF, userRepository.findByNameAndAge(FFF, 60).getName());// 测试删除姓名为AAA的UseruserRepository.delete(userRepository.findByName(AAA));// 测试findAll, 查询所有记录, 验证上面的删除是否成功Assert.assertEquals(9, userRepository.findAll().size());}}因为我们在实体类中通过Max注解为User的age设置了最大值为50这样就可以通过创建User实体的age属性超过50的时候就可以触发异常,也就是我在上边测试类的执行年龄大于50岁的数据都会被终止
HHH000346: Error during managed flush [Validation failed for classes [com.miaow.demo.User] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[ConstraintViolationImpl{interpolatedMessage最大不能超过50, propertyPathage, rootBeanClassclass com.miaow.demo.User, messageTemplate{javax.validation.constraints.Max.message}}
]]如果我们去查数据库表会发现只存在包含50岁以下的所有数据其他数据就添加失败了。
这个时候我们就需要进行事务处理了因为他插入了50岁以前的但是50岁以后的都没了这样就不满足事务的原子性了要么都做要么都不做我们可以通过Transactional来实现,之后我们在瞅瞅数据库表中数据我们发现在没加Transactional的时候他会执行一部分另一部分不执行也就是不满足我们事务中的原子性在我们加了Transactional当我们执行收到阻碍的时候或者被异常终止的时候会使用Rollback注解让我们的相关类都可以在结束的时候得到回滚也就是这件事情要么做要做就要做成功要么不做。
事务的隔离级别
说到了事务那么我们需要提及的是隔离级别事务的隔离级别是我们的数据库管理系统中用来控制并访问数据的一种机制他定义了事务在同时访问数据库的时候对其他事务的影响程度和可以见性的一种规则。
我们常见的隔离级别
读未提交Read Uncommitted最低的隔离级别允许一个事务读取另一个事务未提交的数据。可能会导致脏读Dirty Read问题。读已提交Read Committed保证一个事务只能读取到已经提交的数据。避免了脏读问题但可能会导致不可重复读Non-repeatable Read问题。可重复读Repeatable Read保证一个事务在执行期间多次读取同样的数据时能够得到一致的结果。避免了不可重复读问题但可能会导致幻读Phantom Read问题。串行化Serializable最高的隔离级别通过强制事务串行执行来避免并发问题。可以避免脏读、不可重复读和幻读问题但会降低并发性能。
package org.springframework.transaction.annotation;import org.springframework.transaction.TransactionDefinition;/*** Enumeration that represents transaction isolation levels for use* with the {link Transactional} annotation, corresponding to the* {link TransactionDefinition} interface.** author Colin Sampaleanu* author Juergen Hoeller* since 1.2*/
public enum Isolation {/*** Use the default isolation level of the underlying datastore.* All other levels correspond to the JDBC isolation levels.* see java.sql.Connection*/DEFAULT(TransactionDefinition.ISOLATION_DEFAULT),/*** A constant indicating that dirty reads, non-repeatable reads and phantom reads* can occur. This level allows a row changed by one transaction to be read by* another transaction before any changes in that row have been committed* (a dirty read). If any of the changes are rolled back, the second* transaction will have retrieved an invalid row.* see java.sql.Connection#TRANSACTION_READ_UNCOMMITTED*/READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED),/*** A constant indicating that dirty reads are prevented; non-repeatable reads* and phantom reads can occur. This level only prohibits a transaction* from reading a row with uncommitted changes in it.* see java.sql.Connection#TRANSACTION_READ_COMMITTED*/READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED),/*** A constant indicating that dirty reads and non-repeatable reads are* prevented; phantom reads can occur. This level prohibits a transaction* from reading a row with uncommitted changes in it, and it also prohibits* the situation where one transaction reads a row, a second transaction* alters the row, and the first transaction rereads the row, getting* different values the second time (a non-repeatable read).* see java.sql.Connection#TRANSACTION_REPEATABLE_READ*/REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ),/*** A constant indicating that dirty reads, non-repeatable reads and phantom* reads are prevented. This level includes the prohibitions in* {code ISOLATION_REPEATABLE_READ} and further prohibits the situation* where one transaction reads all rows that satisfy a {code WHERE}* condition, a second transaction inserts a row that satisfies that* {code WHERE} condition, and the first transaction rereads for the* same condition, retrieving the additional phantom row in the second read.* see java.sql.Connection#TRANSACTION_SERIALIZABLE*/SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE);private final int value;Isolation(int value) {this.value value;}public int value() {return this.value;}
}针对这个枚举类我们来看一下我们的Spring Boot的Transaction 中定义的5个表示隔离级别值
public enum Isolation {DEFAULT(-1),READ_UNCOMMITTED(1),READ_COMMITTED(2),REPEATABLE_READ(4),SERIALIZABLE(8);
}DEFAULT这是默认值表示使用底层数据库的默认隔离级别。对大部分数据库而言通常这值就是READ_COMMITTED。READ_UNCOMMITTED该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读和不可重复读因此很少使用该隔离级别。READ_COMMITTED该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读这也是大多数情况下的推荐值。REPEATABLE_READ该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。SERIALIZABLE所有的事务依次逐个执行这样事务之间就完全不可能产生干扰也就是说该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
传播行为
所谓的事务传播行为值的是如果在开始执行当前事务之前一个事务上下文以及存在此时若有若干选项可以指定一个事务性方法的执行行为。
package org.springframework.transaction.annotation;import org.springframework.transaction.TransactionDefinition;/*** Enumeration that represents transaction propagation behaviors for use* with the {link Transactional} annotation, corresponding to the* {link TransactionDefinition} interface.** author Colin Sampaleanu* author Juergen Hoeller* since 1.2*/
public enum Propagation {/*** Support a current transaction, create a new one if none exists.* Analogous to EJB transaction attribute of the same name.* pThis is the default setting of a transaction annotation.*/REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),/*** Support a current transaction, execute non-transactionally if none exists.* Analogous to EJB transaction attribute of the same name.* pNote: For transaction managers with transaction synchronization,* PROPAGATION_SUPPORTS is slightly different from no transaction at all,* as it defines a transaction scope that synchronization will apply for.* As a consequence, the same resources (JDBC Connection, Hibernate Session, etc)* will be shared for the entire specified scope. Note that this depends on* the actual synchronization configuration of the transaction manager.* see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization*/SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),/*** Support a current transaction, throw an exception if none exists.* Analogous to EJB transaction attribute of the same name.*/MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),/*** Create a new transaction, and suspend the current transaction if one exists.* Analogous to the EJB transaction attribute of the same name.* pbNOTE:/b Actual transaction suspension will not work out-of-the-box* on all transaction managers. This in particular applies to* {link org.springframework.transaction.jta.JtaTransactionManager},* which requires the {code javax.transaction.TransactionManager} to be* made available to it (which is server-specific in standard Java EE).* see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager*/REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),/*** Execute non-transactionally, suspend the current transaction if one exists.* Analogous to EJB transaction attribute of the same name.* pbNOTE:/b Actual transaction suspension will not work out-of-the-box* on all transaction managers. This in particular applies to* {link org.springframework.transaction.jta.JtaTransactionManager},* which requires the {code javax.transaction.TransactionManager} to be* made available to it (which is server-specific in standard Java EE).* see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager*/NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),/*** Execute non-transactionally, throw an exception if a transaction exists.* Analogous to EJB transaction attribute of the same name.*/NEVER(TransactionDefinition.PROPAGATION_NEVER),/*** Execute within a nested transaction if a current transaction exists,* behave like PROPAGATION_REQUIRED else. There is no analogous feature in EJB.* pNote: Actual creation of a nested transaction will only work on specific* transaction managers. Out of the box, this only applies to the JDBC* DataSourceTransactionManager when working on a JDBC 3.0 driver.* Some JTA providers might support nested transactions as well.* see org.springframework.jdbc.datasource.DataSourceTransactionManager*/NESTED(TransactionDefinition.PROPAGATION_NESTED);private final int value;Propagation(int value) {this.value value;}public int value() {return this.value;}}事务传播行为是指在多个事务之间进行操作时事务的行为方式。常见的事务传播行为包括
REQUIRED如果当前存在事务则加入该事务如果没有事务则创建一个新的事务。这是默认的传播行为。REQUIRES_NEW无论当前是否存在事务都创建一个新的事务。如果当前存在事务则将其挂起。SUPPORTS如果当前存在事务则加入该事务如果没有事务则以非事务方式执行。NOT_SUPPORTED以非事务方式执行操作如果当前存在事务则将其挂起。MANDATORY如果当前存在事务则加入该事务如果没有事务则抛出异常。NEVER以非事务方式执行操作如果当前存在事务则抛出异常。NESTED如果当前存在事务则在嵌套事务中执行。嵌套事务是外部事务的一部分可以独立提交或回滚但是如果外部事务回滚则嵌套事务也会回滚。
事务传播行为可以根据具体的业务需求来选择以确保事务的一致性和可靠性。不同的传播行为可以在多个事务之间提供灵活的控制和管理。
指定方法通过使用propagation属性设置例如
Transactional(propagation Propagation.REQUIRED)