spring JDBC-事务管理
一、Spring 中的JDBC
Spring中封装了JDBC的ORM框架,可以用它来操作数据,不需要再使用外部的OEM框架(MyBatis),一些小的项目用它。
步骤:
1.导入JDBC相关的Jar包,应用dbcp连接池
aopalliance-1.0.0.jar
aspectjweaver-1.6.8.jar
commons-dbcp-1.4.jar // 数据库连接池
commons-logging-1.1.1.jar
commons-pool-1.5.3.jar
mysql-connector-java-5.1.38-bin.jar
spring-aop-4.3.10.RELEASE.jar
spring-aspects-4.3.10.RELEASE.jar
spring-beans-4.3.10.RELEASE.jar
spring-context-4.3.10.RELEASE.jar
spring-context-support-4.3.10.RELEASE.jar
spring-core-4.3.10.RELEASE.jar
spring-expression-4.3.10.RELEASE.jar
spring-jdbc-4.3.10.RELEASE.jar //jdbc 操作的对象包
spring-tx-4.3.10.RELEASE.jar //数据库中的事务处理包
2.在配置文件中配置连接池数据源,及JdbcTemplate对象
<
!-- 加载连接数据的的属性文件 -->
<bean id="propertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:config/jdbc.properties"/>
</bean>
<!-- 配置数据源对象,此数据源用的是dbcp连接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<!-- 连接数据库的基本配置 ${driver}读取到属性文件的键对应的值-->
<property name="driverClassName" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
<!-- 配置连接池相关属性,初始大小,最大连接数,最大空闲,最小空闲,最大空闲时间 -->
<property name="initialSize" value="${initialSize}"/>
<property name="maxActive" value="${maxActive}"/>
<property name="maxIdle" value="${maxIdle}"/>
<property name="minIdle" value="${minIdle}"/>
<property name="maxWait" value="${maxWait}"/>
</bean>
<!-- Spring框架封装好的JDBC对象,可以操作数据 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
3.在程序中获取到JdbcTemplate对象,此对象就可以操作数据。
@Service // 扫描到IOC容器中
public class GradeService {
@Autowired // 自动从IOC容器中注入对象
JdbcTemplate jdbcTemplate;
// 查询所有
public List<Grade> getGrades() {
String sql = "select * from grade";
// 数据行映射器,映射数据行的列与实体对象的属性对应
RowMapper<Grade> rm = new BeanPropertyRowMapper<>(Grade.class);
// 可以把查询的结果集中的数据行一行行封装成实体对象
List<Grade> grades = jdbcTemplate.query(sql, rm);
return grades;
}
// 根据ID查询单个对象
public Grade getGradeById(int id) {
RowMapper<Grade> rm = new BeanPropertyRowMapper<>(Grade.class);
String sql = "select * from grade where gradeId=?";
return jdbcTemplate.query(sql, new Object[] { id }, rm).get(0);
}
// 根据ID查询年级名称,返回单个值
public String getGradeNameById(int id) {
String sql = "select gradeName from grade where gradeId=?";
return jdbcTemplate.queryForObject(sql, new Object[] { id }, String.class);
}
// 根据年级名称查询ID,返回单个值
public int getGradeIdByName(String name) {
String sql = "select gradeId from grade where gradeName=?";
return jdbcTemplate.queryForObject(sql, new Object[] { name }, int.class);
}
//添加,增,删,改调用相同的方法,只是SQL指令不同
public int add(Grade g) {
String sql = "insert into grade values(null,?)";
return jdbcTemplate.update(sql, g.getGradeName());
}
}
二、事务管理
事务是数据库中的事务,在数据库中,每一个SQL指令都是独立的事务,数据库的事务类型自动提交型,
事务有4大特性:原子性,一致性,隔离性,持久性。
有时,我们一个业务逻辑需要多条SQL指令一起完成,比如下订单,先向订单表插入一条数,再根据生成的订单号,再向订单详细表插入数据,就需要多条SQL语句支撑。但是数据库认为每一条SQL指令是一个事务,假如一条SQL有问题不能执行,不会影响的SQL指令执行的。只有用事务才可以控制。事务的作用是把一批SQL指令作为一个整体,一起执行或不执行。
转账功能,修改的SQL语句就需要2条,向交易表插入至少1条SQL语句。
在开发中,我们用自定义事务来处理一次要执行多条SQL指令的业务。
事务管理的步骤:
1.在配置文件中配置事务管理机制:
<!-- 启用事务管理器 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 配置事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
2.建议在业务层的方法前加入 @Transactional注解,此注解的作用是把方法里面的所有操作数据库的SQL指令整合为一个事务。
/**
* 事务管理,此方法里面所有的操作数据库的SQL指令整合为一个事务
* @Transactional这个注解可以在方法前,也可以在类前。
* 加在方法前,表示此方法应用事务机制,在类前,则这个类中所有的方法都应用事务机制
*/
@Transactional
public void zhanzhang(String INbank,String OUTbank,double money) {
try {
bankDao.inMoney(INbank, money);
bankDao.outMoney(OUTbank, money);
System.out.println("转账成功!");
} catch (Exception e) {
System.out.println("转账失败,原因是:" + e.getMessage());
}
}
三、事务超时设置:
@Transactional(timeout=30) //默认是30秒
四、事务隔离级别:
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
读取未提交数据( 会出现脏读, 不可重复读) 基本不使用
@Transactional(isolation = Isolation.READ_COMMITTED)
读取已提交数据(会出现不可重复读和幻读)
@Transactional(isolation = Isolation.REPEATABLE_READ)
可重复读(会出现幻读)
@Transactional(isolation = Isolation.SERIALIZABLE)
串行化
MYSQL: 默认为REPEATABLE_READ级别
SQLSERVER: 默认为READ_COMMITTED
五、事务传播行为
@Transactional(propagation=Propagation.REQUIRED)
如果有事务, 那么加入事务, 没有的话新建一个(默认)
@Transactional(propagation=Propagation.NOT_SUPPORTED)
容器不为这个方法开启事务
@Transactional(propagation=Propagation.REQUIRES_NEW)
不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务
@Transactional(propagation=Propagation.MANDATORY)
必须在一个已有的事务中执行,否则抛出异常
@Transactional(propagation=Propagation.NEVER)
必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)
@Transactional(propagation=Propagation.SUPPORTS)
如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务.
上一篇: ExtJS下grid的一些属性说明
下一篇: https应用总结