Spring - 09JdbcTemplate及事务
(1)JdbcTemplate基本使用
JdbcTemplate是Spring框架提供的一个对象,是对原始繁琐的Jdbc API对象的简单封装。Spring框架为我们提供了很多的操作模板类。
例如:操作关系数据库的JdbcTemplate和HibernateTemplate,操作Redis的RedisTemplate,操作消息队列的JmsTemplate等等。
(1.1)导入spring-jdbc和spring-tx坐标
导入spring-context、spring-test、junit、mysql-connector-java、c3p0、druid
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.0.10.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.0.10.RELEASE</version> </dependency>
(1.2)创建数据库表和实体
public class Account {
private String name;
private double money;
// 省略getter/setter/toString
}
(1.3)创建JdbcTemplate对象
@Test
public void test1(){
DruidDataSource dataSource = new DruidDataSource(); // 创建数据源对象
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/dev");
dataSource.setUsername("root");
dataSource.setPassword("Mysql2020");
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource); // 设置数据源对象,知道数据库在哪
int row = jdbcTemplate.update("insert into account values(?,?)", "tom", 5000.00);
System.out.println(row);
}
(1.4)执行数据库操作
JdbcTemplate jdbcTemplate = new JdbcTemplate(); jdbcTemplate.setDataSource(dataSource); int row = jdbcTemplate.update("insert into account values(?,?)", "tom", 5000.00); System.out.println(row);
(1.5)Spring产生JdbcTemplate对象
我们可以将JdbcTemplate的创建权交给Spring,将数据源DataSource的创建权也交给Spring,在Spring容器内部将数据源DataSource注入到JdbcTemplate模板对象中。
<context:property-placeholder location="classpath:jdbc.properties"/> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> // 数据源对象 <property name="driverClass" value="${jdbc.driver}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> // jdbc模板对象 <property name="dataSource" ref="dataSource"></property> </bean>
@Test public void test2() throws PropertyAccessException { ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml"); JdbcTemplate jdbcTemplate = app.getBean(JdbcTemplate.class); int row = jdbcTemplate.update("insert into account values(?,?)", "xiaoming", 4000); System.out.println(row); }
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class JdbcTemplateTest { @Autowired private JdbcTemplate jdbcTemplate; @Test public void testQueryCount(){ Long count = jdbcTemplate.queryForObject("select count(*) from account", Long.class); System.out.println(count); } @Test public void testQueryOne(){ Account account = jdbcTemplate.queryForObject("select * from account where name = ?", new BeanPropertyRowMapper<Account>(Account.class),"tom"); System.out.println(account); } @Test public void testQueryAll(){ List<Account> accountList = jdbcTemplate.query("select * from account", new BeanPropertyRowMapper<Account>(Account.class)); System.out.println(accountList); } @Test public void testDelete(){ int row = jdbcTemplate.update("delete from account where name = ?", "aaa"); System.out.println(row); } @Test public void testUpdate(){ int row = jdbcTemplate.update("update account set money = ? where name = ?", 8000,"xiaoming"); System.out.println(row); } }
(2)编程式事务控制对象
(2.1)PlatformTransactionManager
PlatformTransactionManager接口是Spring的事务管理,它里面提供了我们常用的操作事务的方法。
public interface PlatformTransactionManager extends TransactionManager { // 获取事务的状态信息 TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; // 提交事务 void commit(TransactionStatus status) throws TransactionException; // 回滚事务 void rollback(TransactionStatus status) throws TransactionException; }
PlatformTransactionManager 是接口类型,不同的Dao层技术有不同的实现类。
Dao层技术为jdbc或mybatis时, 为 org.springframework.jdbc.datasource.DataSourceTransactionManager
Dao层技术为hibernate时, 为 org.springframework.orm.hibernate5.HibernateTransactionManager
(2.2)TransactiionDefinition
TransactionDefinition 是事务的定义信息对象,里面的方法如下:
| 方法 | 说明 |
|
int getIsolationLevel()
|
获取事务的隔离级别 |
|
int getPropogationBehavior()
|
获取事务的传播行为 |
|
int getTimeout()
|
获取超时时间 |
| boolean isReadOnly() | 是否只读 |
事务隔离级别:
1> 解决事务并发产生的问题,如脏读、不可重复读和幻读。
2> ISOLATION_DEFAULT、ISOLATION_READ_UNCOMMITTED、ISOLATION_READ_COMMITTED、ISOLATION_REPEATABLE_READ、ISOLATION_SERIALIZABLE
事务传播行为
1> REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值)
2> SUPPORTS:支持当前的事务,如果当前没有事务,就以非事务方式执行(没有事务)
3> MANDATORY:使用当前的事务,如果当前没有事务,则抛出异常
4> REQUERS_NEW:新建事务,如果当前在事务中,把当前事务挂起
5> NOT_SUPPORTED:以非事务方式执行操作,如果当期存在事务,就把当前事务挂起
6> NEVER: 以非事务方式执行,如果当前存在事务,抛出异常。
7> NESTED: 如果当前存在事务,则在嵌套事务内执行。如果当期没有事务,则只写REQUIRED类似的操作
超时时间: 默认值为-1,没有超时限制。如果有,以秒为单位进行设置。
是否只读: 建议查询设置为只读。
(2.3)TransactionStatus
TransactionStatus接口提供的是事务具体的运行状态。
public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable { // 是否是新事务 @Override boolean isNewTransaction(); // 是否存储回滚点 boolean hasSavepoint(); @Override void setRollbackOnly(); // 事务是否回滚 @Override boolean isRollbackOnly(); void flush(); // 事务是否完成 @Override boolean isCompleted(); }
(3)基于XML的声明式事务控制
(3.1)什么是声明式事务控制
采用声明的方式来处理事务。声明是指在配置文件中声明,用在Spring配置文件中声明式的处理事务来代替代码式的处理事务。
> 事务管理不侵入开发的组件。业务逻辑对象不会意识到正在事务管理之中。事务管理是属于系统层面的服务,不是业务逻辑的一部分。
> 在不需要事务管理时,只要在配置文件上修改一下,即可移去事务管理服务,无需改变代码重新编辑,维护方便。
> 注意: Spring声明式事务控制底层就是AOP。
(3.2)引入坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.10.RELEASE</version>
</dependency>
(3.3)编写业务代码
public class AccountDaoImpl implements AccountDao { private JdbcTemplate jdbcTemplate; public void setJdbcTemplate(JdbcTemplate jdbcTemplate){ this.jdbcTemplate = jdbcTemplate; } public void out(String outMan, double money) { jdbcTemplate.update("update account set money=money-? where name=?",money,outMan); } public void in(String inMan, double money) { jdbcTemplate.update("update account set money=money+? where name=?",money,inMan); } }
public class AccountServiceImpl implements AccountService { private AccountDao accountDao; public void setAccountDao(AccountDao accountDao){ this.accountDao = accountDao; } public void transfer(String outMan, String inMan, double money) { accountDao.out(outMan,money);
// int i = 1/0; // 此处抛出异常,造成outMan的money 减少,而inMan的money 没有增加 accountDao.in(inMan,money); } }
public class AccountController { public static void main(String[] args) { ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml"); AccountService accountService = app.getBean(AccountService.class) ; accountService.transfer("tom","xiaoming",500); } }
(3.4)配置事务
<context:property-placeholder location="classpath:jdbc.properties"/> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="accountDao" class="com.bearpx.spring.tx.dao.impl.AccountDaoImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"></property> </bean> <bean id="accountService" class="com.bearpx.spring.tx.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean>
// 配置平台事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> // 通知: 事务增强 <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> // 设置事务的属性信息 <tx:method name="findAll" isolation="DEFAULT" propagation="REQUIRED" timeout="-1" read-only="false"/> <tx:method name="update*" isolation="DEFAULT" propagation="REQUIRED" timeout="-1" read-only="false"/> <tx:method name="*"></tx:method> </tx:attributes> </tx:advice> // 配置事务的aop织入 <aop:config> <!--<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.bearpx.spring.tx.service.impl.*.*(..))"></aop:advisor>--> <aop:pointcut id="txPointcut" expression="execution(* com.bearpx.spring.tx.service.impl.*.*(..))"></aop:pointcut> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/> </aop:config>
(4)基于注解的声明式事务控制
(4.1)修改注解方式
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public void out(String outMan, double money) {
jdbcTemplate.update("update account set money=money-? where name=?",money,outMan);
}
public void in(String inMan, double money) {
jdbcTemplate.update("update account set money=money+? where name=?",money,inMan);
}
}
@Service("accountService")
@Transactional(isolation = Isolation.REPEATABLE_READ) // 在类上设置事务属性
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
// 在方法上设置事务熟悉
// @Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
public void transfer(String outMan, String inMan, double money) {
accountDao.out(outMan,money);
// int i = 1/0;
accountDao.in(inMan,money);
}
}
(4.2)修改配置文件
<context:component-scan base-package="com.bearpx"/> //组件扫描 <context:property-placeholder location="classpath:jdbc.properties"/> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <bean id="jdbcTempalte" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> // 平台事务管理器 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> // 事务的注解驱动 <tx:annotation-driven transaction-manager="transactionManager"/>
浙公网安备 33010602011771号