欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

spring JDBC-事务管理

程序员文章站 2022-03-07 11:07:18
...

一、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没有声明事务,那就不用事务.

相关标签: spring框架