Spring JDBC
一.基本用法
1.1 添加依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
1.2配置Dao
DataSource-->JdbcTemplate-->Dao-->Service-->Action
1.3配置DataSource
DataSource的实现方式:
- 使用Spring提供的数据源(DriverManagerDataSource),没有连接池的功能,效率低
- 使用第三方的数据源,如:dbcp,c3p0,druid(德鲁伊)
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
二、用户注册
JDBC默认是自动提交数据的,每执行完一条sql语句就提交事务
解决:配置事务
Spring事务管理
一、两种方式
定义事务管理器,相当于事务的通知
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
- 方式1:基于命名空间
<!--定义通知,并指定事务管理器-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--配置事务属性-->
<tx:attributes>
<tx:method name="login" propagation="SUPPORTS" read-only="true"/>
<tx:method name="regist" propagation="REQUIRED" isolation="READ_COMMITTED" no-rollback-for="java.lang.ArithmeticException"
timeout="5000" />
</tx:attributes>
</tx:advice>
<aop:config>
<!--配置切入点-->
<aop:pointcut id="pc" expression="execution(* com.hxx.service.impl.*.*(..))"/>
<!--进行织入-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/>
</aop:config>
- 方式2:基于注解
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = NullPointerException.class,
timeout = 5000)
<!--配置注解驱动-->
<tx:annotation-driven transaction-manager="transactionManager"/>
二、事务属性
五个事务属性:
-
传播属性
propagation:定义事务的边界,用来定义当前方法是否需要事务。
常用取值:- REQUIRED:必须添加事务,如果当前没有事务,则创建一个新的事务,一般用于增删改操作。
- SUPPORTS:可以没有事务,如果当前有事务则运行,如果没有事务也可以运行,一般用于查询操作。
-
隔离级别
isolation:用来解决事务并发时会出现的一些问题。
四种隔离级别:- TRANSACTION_READ_COMMITTED:已提交读——>可以避免脏读,但是可能发生不可重复读和幻读。
- TRANSACTION_READ_UNCOMMITTED:未提交读——>可能会发生脏读,不可重复读和幻读。
- TRANSACTION_REPEATABLE_READ:可重复读——>可避免脏读和不可重复读,但可能会发生幻读。
- TRANSACTION_SERIALIZABLE:可序列化——>可以避免脏读,不可重复读和幻读,相当于单并发,没意义。
事务并发时可能会出现的三个问题:
- 脏读:一个事务读取到另一个事务没有提交的数据,一般不会发生,如MySql、Oracle底层默认只允许读取已经提交的数据。
- 不可重复读:一个事务已经读取数据,另一个事务在修改数据,可能导致使用的数据与数据库中不同步。
- 虚读或幻读:一个事务已经读取数据,另外一个事务在添加或删除数据,可能导致数据量与数据库不同步。
注意:不可重复读和幻读是小概率事件,发生的几率比较低。可以通过版本检查来解决,如:Hibernate中的悲观锁和乐观锁就是通过版本检查来实现的,不但麻烦而且效率还低。实际开发中一般不需要配置隔离级别,大多是通过定时任务+人工审核。
回滚条件
rollback:默认抛出RuntimeException时才会回滚
rollbackFor=""表示发生该异常时回滚
norollbackFor=""表示发生该异常时不回滚只读优化
readOnly:在该事务中只允许读取数据,一般用于查询超时处理
timeout:配置事务的超时时间,一般不配置
三、事务特性
四个事务特性:ACID 原子性、一致性、隔离性、永久性