Spring整理三

    技术2024-10-29  25

    Spring JDBC 框架

    1、前言

    在使用普通的 JDBC 数据库时,就会很麻烦的写不必要的代码来处理异常,打开和关闭数据库连接等。

    Spring 框架针对数据库开发中的应用提供了 JDBCTemplate 类,该类是 Spring 对 JDBC 支持的核心,它提供了所有对数据库操作功能的支持。

    Spring 框架提供的JDBC支持主要由四个包组成,分别是 core(核心包)、object(对象包)、dataSource(数据源包)和 support(支持包),org.springframework.jdbc.core.JdbcTemplate 类就包含在核心包中。

    2、核心类

    JdbcTemplate 类继承自抽象类 JdbcAccessor,同时实现了 JdbcOperations 接口。其直接父类 JdbcAccessor 为子类提供了一些访问数据库时使用的公共属性,具体介绍如下:

    DataSource 其主要功能是获取数据库连接,具体实现时还可以引入对数据库连接的缓冲池和分布式事务的支持,它可以作为访问数据库资源的标准接口。SQLExceptionTranslator org.springframework.jdbc.support.SQLExceptionTranslator 接口负责对 SQLException 进行转译工作。通过必要的设置或者获取 SQLExceptionTranslator 中的方法,可以使 JdbcTemplate 在需要处理 SQLException 时,委托 SQLExceptionTranslator 的实现类完成相关的转译工作。

    JdbcOperations 接口定义了在 JdbcTemplate 类中可以使用的操作集合,包括添加、修改、查询和删除等操作。

    JdbcDaoSupport则对JdbcTemplate进行了封装,所以要操作JdbcTemplate,或只需要继承JdbcDaoSupport即可。

    3、示例

    首先引入jar包:spring-jdbc、org.springframework.transaction、org.springframework.jdbc、mysql-connector-java https://mvnrepository.com/artifact/mysql/mysql-connector-java

    事务管理

    1、前言

    事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。

    例如:在关系数据库中,一个事务可以是一条SQL语句,一组SQL语句或整个程序。

    比如我有一个业务,需要先对数据库插入数据再修改数据,假如这时修改失败了,这会导致数据出错。此时加上事物,当这两条操作只要有一个出现问题,那就全部回滚,所有数字都不写入数据库。

    一个数据库事务是一个被视为单一的工作单元的操作序列。这些操作应该要么完整地执行,要么完全不执行。以确保数据完整性和一致性。

    因此,事务应该具有4个属性:原子性、一致性、隔离性、持续性。这四个属性通常称为ACID特性:

    原子性: 事务应该当作一个单独单元的操作,这意味着整个序列操作要么是成功,要么是失败的。一致性: 指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。 拿转账来说,假设A和B加起来一共5000元,那么不管A和B之间如何转账,转几次账,事务结束后两人的钱相加起来应该还得是5000,不能因为转到一半系统宕机了,导致A扣了1000,但是B没收到,这就是事务的一致性。 隔离性: 可能同时处理很多有相同的数据集的事务,每个事务应该与其他事务隔离,以防止数据损坏。 同转账,A有1000元,此时B给A转了500,结果还没转完,C又给A转了200,此时B完成时A有1500,B完成时A变成了1200,缺了500,这是因为B是按照A有1000算的。 持久性: 一个事务一旦完成全部操作后,这个事务的结果必须是永久性的,不能因系统故障而从数据库中删除。

    事务分局部事物和全局事务:局部事务是特定于一个单一的事务资源,如一个 JDBC 连接,而全局事务可以跨多个事务资源事务,如在一个分布式系统中的事务。

    2、Spring的事务

    1、 支持两种类型的事务管理:编程式和声明式

    编程式:自己手动控制事务。

    属于细粒度的事务控制,可以对指定的方法、指定的方法的某几行添加事务控制。使用比较灵活,但开发起来比较繁琐, 每次都要开启、提交、回滚,维护也麻烦。开启事务后一定要手动释放(提交或回滚),否则长期占用内存,有可能报事务异常。

    声明式:Spring提供使用注释或 XML 配置来管理事务,让事务从业务代码中分离。

    属于粗粒度的事务控制, 只能给整个方法应用事务,不可以对方法的某几行应用事务。不想使用时直接移除配置,实现了对事务控制的最大程度的解耦。核心实现基于Aop。Spring的事务属性分别为传播行为、隔离级别、只读和超时属性,这些属性提供了事务应用的方法和描述策略。

    3、Spring事务的核心

    1、核心接口: spring-tx是Spring提供的用于事务管理的jar包,其中包括事务管理的三个核心接口:PlatformTransactionManager、TransactionDefinition 和 TransactionStatus。

    PlatformTransactionManager接口是Spring提供的平台事务管理器,用于管理事务。该接口中提供了三个事务操作方法: TransactionStatus getTransaction(TransactionDefinition definition):用于获取事务状态信息。void commit(TransactionStatus status):用于提交事务。void rollback(TransactionStatus status):用于回滚事务。在项目中,Spring 将 xml 中配置的事务详细信息封装到对象 TransactionDefinition 中,然后通过事务管理器的 getTransaction() 方法获得事务的状态(TransactionStatus),并对事务进行下一步的操作。 TransactionDefinition 接口是事务定义(描述)的对象,它提供了事务相关信息获取的方法,其中包括五个操作 String getName():获取事务对象名称。int getIsolationLevel():获取事务的隔离级别。int getPropagationBehavior():获取事务的传播行为。int getTimeout():获取事务的超时时间。boolean isReadOnly():获取事务是否只读。 TransactionStatus 接口是事务的状态,它描述了某一时间点上事务的状态信息: boolean hasSavepoint():获取是否存在保存点。boolean isCompleted() :获取事务是否完成。boolean isNewTransaction() :获取是否是新事务。boolean isRollbackOnly() :获取是否回滚。void setRollbackOnly(): 设置事务回滚。void flush():刷新事务。

    2、传播行为 在事务管理过程中,传播行为可以控制是否需要创建事务以及如何创建事务。 通常情况下,数据的查询不会改变原数据,所以不需要进行事务管理,而对于数据的增加、修改和删除等操作,必须进行事务管理。如果没有指定事务的传播行为,则 Spring3 默认的传播行为是 required。

    3、隔离级别

    事务的并发操作中可能会出现脏读,不可重复读,幻读:

    脏读(误读):事务A更新了某个数据项X,但是由于某种原因,事务A出现了问题,于是要把A回滚。但是在回滚之前,另一个事务B读取了数据项X的值(A更新后),A回滚了事务,数据项恢复了原值。事务B读取的就是数据项X的就是一个“临时”的值,就是脏数据,这就是脏读。不可重复读:是指在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。是由于查询时系统中其他事务修改的提交而引起的。比如事务T1读取某一数据,事务T2读取并修改了该数据,T1为了对读取值进行检验而再次读取该数据,便得到了不同的结果。对应的是UPDATE操作。幻读(虚读):指当事务不是独立执行时发生的一种现象。例如,A事务对一个表中的全部数据进行了修改。同时,B事务向这个表中插入一行新的数据。那么,以后就会发生操作A事务的用户发现表中还有没有修改的数据行,就好像发生了幻觉一样。对应INSERT操作。

    ISOLATION_DEFAULT:默认隔离级别。

    大多数数据库默认的事务隔离级别是Read committed(读提交),比如Sql Server , Oracle。Mysql的默认隔离级别是Repeatable read(重复读)。

    ISOLATION_READ_UNCOMMITTED:读未提交

    一个事务可以读取另一个未提交事务的数据。可能发生脏读、不可重复读和幻读。

    ISOLATION_READ_COMMITTED:读提交

    一个事务要等另一个事务提交后才能读取数据。能够阻止脏读;但可能发生不可重复读和幻读。

    ISOLATION_REPEATABLE_READ:重复读

    在开始读取数据(事务开启)时,不再允许修改操作。能够阻止脏读、不可重复读;但可能发生幻读。

    ISOLATION_SERIALIZABLE:序列化

    是最高的事务隔离级别,在该级别下,事务串行化顺序执行。能够阻止脏读、不可重复读、幻读。效率低下,比较耗数据库性能,一般不使用。

    4、编程式事务

    直接使用 PlatformTransactionManager 来实现编程式事务。要开始一个新事务,你需要有一个带有适当的 transaction 属性的 TransactionDefinition 的实例。

    当 TransactionDefinition 创建后,可以通过调用 getTransaction() 方法来开始事务,该方法会返回 TransactionStatus 的一个实例。 TransactionStatus 对象帮助追踪当前的事务状态,并且最终,如果一切运行顺利,可以使用 PlatformTransactionManager 的 commit() 方法来提交这个事务,否则的话,可以使用 rollback() 方法来回滚整个操作。

    让我们把上边jdbc的例子改改就可以实现:引入spring-tx包 修改StudentJDBCTemplate,添加事务相关的实现。 修改xml配置: 此时运行后你会发现数据库里没有插入数据。当你把rollback方法修改为commit才可插入。

    5、声明式事务

    由于在实际开发中,编程式事务管理很少使用,所以重点看看 Spring 的声明式事务管理。

    Spring 声明式事务管理在底层采用了 AOP 技术,其最大的优点在于无须通过编程的方式管理事务,只需要在配置文件中进行相关的规则声明,就可以将事务规则应用到业务逻辑中。

    Spring 实现声明式事务管理主要有两种方式:

    1、基于XML方式实现:整体上还是改造上边的例子,但因为比较重要,还是贴全了 2、基于Annotation注解方式实现 使用注解则及其简单: 1)、在 Spring 容器中注册驱动,<tx:annotation-driven transaction-manager=“txManager”/>,后边事务管理器可写可不写。2)、在需要使用事务的业务类或者方法中添加注解 @Transactional,并配置 @Transactional 的参数。 注意开启注解,因为我在xml里有配置StudentJDBCTemplate的bean,所以就没开注解扫描。
    Processed: 0.012, SQL: 9