Spring·JdbcTemplate & 事务

CY 2018年02月04日 634次浏览

使用SpringDataJPA的时候,总是会遇到一些复杂的查询情况,比如说需要按照传入的参数拼装SQL,如果参数为null就不拼装这段SQL,并且同时还要使用数据库中的自定义函数来辅助完成查询时的计算,这个时候用JpaSpecification都已经无法解决问题了,就算在Repository实体类上使用@Query注解来规定死查询语句,那么判断参数为null或者空字符串也要做很多工作,可能会使用很多的IF()函数,这就让SQL的可读性变得更加差劲。

所以这个时候需要尽量回归原生,使用JdbcTemplate,但是一定要避免SQL注入攻击,还要拥有JPA那样的SQL参数(例如::username),所以总结一下正确的JdbcTemplate的使用方式。

使用JdbcTemplate

Spring提供了两种JdbcTemplate

org.springframework.jdbc.core.JdbcTemplate普通的JdbcTemplate

org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate可以传递具名参数的JdbcTemplate,例如::username

防止SQL注入的使用方式

使用XML配置JdbcTemplate

如果数据层有很多的类,每个类都需要JdbcTemplate,那么需要使用XML为每个类都注入一个JdbcTemplate,这就相当的费事了,Spring提供了一个JdbcDaoSupport类,可以让数据层来继承,类中提供了一个getJdbcTemplate()方法,可以直接获取JdbcTemplate,这就解决了数据层每个类都要注入一个JdbcTemplate的问题。

对于事务的补充说明

关于事务的隔离级别,网上的教程特别的多了,就不总结了。

【参考连接】廖雪峰SQL教程事务部分

Spring也提供了对于隔离级别的支持:

  • ISOLATION_DEFAULT:默认级别,用数据库默认的级别
  • ISOLATION_READ_UNCOMMITTED:可以读取未提交的数据
  • ISOLATION_READ_COMMITTED:只能读取已经提交的数据,解决了脏读的问题
  • ISOLATION_REPEATABLE_READ:是否读取其他事务修改提交后的数据,解决不可重复读的问题
  • ISOLATION_SERIALIZABLE:是否读取其他事务添加提交后的数据,解决幻读的问题

Spring也提供了事务的传播行为:

  • REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值)
  • SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)
  • MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常
  • REQUERS_NEW:新建事务,如果当前在事务中,把当前事务挂起。
  • NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
  • NEVER:以非事务方式运行,如果当前存在事务,抛出异常
  • NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作。

同时也提供了超时时间,如果设置为-1就是没有限制,以秒为单位。

提供了设置是否为只读事务,查询的时候开启就可以了。

XML文件的概述如下

tx:advice:标签 用来配置事务增强

  • id:事务增强的唯一标识
  • transaction-manager:事务管理类实例,比如说DataSourceTransactionManager

tx:advice拥有子标签tx:attributes

tx:attributes的子标签tx:method的属性

  • read-only:是否是只读事务。默认 false,不只读。
  • isolation:指定事务的隔离级别。默认值是使用数据库的默认隔离级别。
  • propagation:指定事务的传播行为。
  • timeout:指定超时时间。默认值为: -1。永不超时。
  • rollback-for:用于指定一个异常,当执行产生该异常时,事务回滚。产生其他异常,事务不回滚。没有默认值,任何异常都回滚。
  • no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时,事务回 滚。没有默认值,任何异常都回滚。

若要开启事务,需要配置AOP

<!-- 配置 aop -->
<aop:config>
    <!-- 配置切入点表达式 -->
    <aop:pointcut expression="execution(* com.cy.service.*.*(..))" id="transactionPointcut"/>
    <!-- 建立事务的通知和切入点表达式的关系 -->
    <aop:advisor advice-ref="txAdvice" pointcut-ref="transactionPointcut"/>
</aop:config>

若要使用注解

// 作用在方法,类,接口上,优先级:方法 > 类 > 接口
@Transactional(readOnly=true, propagation=Propagation.SUPPORTS)
@Transactional(readOnly=false, propagation=Propagation.REQUIRED)
// 允许使用事务管理,SpringBoot项目不用写
@EnableTransactionManagement