1. jdbcTemplate
1.1 基本概念
-
JdbcTemplate是spring框架中提供的一个模板对象,是对原始繁琐的Jdbc API对象的简单封装
-
核心对象
JdbcTemplate jdbcTemplate = new JdbcTemplate(DataSource dataSource);
-
核心方法
执行增、删、改语句 int update(); // // 查询多个 List<T> query(); // 查询一个 T queryForObject(); // 实现ORM映射封装 new BeanPropertyRowMapper<>();
1.2 Spring整合
1.2.1 Maven配置
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.15</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.15</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.15</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.15</version>
</dependency>
</dependencies>
1.2.2 实体类
-
Account
public class Account { private Integer id; private String name; private Double money; }
1.2.3 Dao层接口
-
AccountDao
package cn.knightzz.dao; import cn.knightzz.entity.Account; import java.util.List; public interface AccountDao { /** * 查询所有账户 * @return */ public List<Account> findAll(); /** * 根据id查询账户 * @param id * @return */ public Account findById(Integer id); /** * 添加账户信息 * @param account */ public void save(Account account); /** * 更新账户信息 * @param account */ public void update(Account account); /** * 删除账户信息 * @param id */ public void delete(Integer id); }
-
AccountDaoImpl
package cn.knightzz.dao.impl; import cn.knightzz.dao.AccountDao; import cn.knightzz.entity.Account; import org.springframework.beans.factory.BeanFactory; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import javax.annotation.Resource; import java.util.List; /** * @author 王天赐 * @title: AccountDaoImpl * @projectName mybatis-apply-06 * @description: * @website http://knightzz.cn/ * @github https://github.com/knightzz1998 * @date 2022/1/27 14:07 */ @Repository("accountDao") public class AccountDaoImpl implements AccountDao { @Resource JdbcTemplate jdbcTemplate; @Override public List<Account> findAll() { String sql = "select * from account"; List<Account> accountList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Account.class)); return accountList; } @Override public Account findById(Integer id) { String sql = "select * from account where id = ?"; Account account = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(Account.class), id); return account; } @Override public void save(Account account) { String sql = "insert into account(id, name ,money) values(null , ?, ?)"; jdbcTemplate.update(sql, account.getName(), account.getMoney()); } @Override public void update(Account account) { String sql = "update account set name = ?, money = ? where id = ?"; jdbcTemplate.update(sql, account.getName(), account.getMoney(), account.getId()); } @Override public void delete(Integer id) { String sql = "delete from account where id = ?"; jdbcTemplate.update(sql, id); } }
1.3.4 Service 层接口
-
AccountService接口
package cn.knightzz.service; import cn.knightzz.entity.Account; import java.util.List; public interface AccountService { /** * 查询所有账户 * @return */ public List<Account> findAll(); /** * 根据id查询账户 * @param id * @return */ public Account findById(Integer id); /** * 添加账户信息 * @param account */ public void save(Account account); /** * 更新账户信息 * @param account */ public void update(Account account); /** * 删除账户信息 * @param id */ public void delete(Integer id); }
-
AccountServiceImpl
package cn.knightzz.service.impl; import cn.knightzz.dao.AccountDao; import cn.knightzz.entity.Account; import cn.knightzz.service.AccountService; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.List; @Service("accountService") public class AccountServiceImpl implements AccountService { @Resource AccountDao accountDao; @Override public List<Account> findAll() { return accountDao.findAll(); } @Override public Account findById(Integer id) { return accountDao.findById(id); } @Override public void save(Account account) { accountDao.save(account); } @Override public void update(Account account) { accountDao.update(account); } @Override public void delete(Integer id) { accountDao.delete(id); } }
1.3.5 测试代码
-
AccountServiceTest
package cn.knightzz.service; import cn.knightzz.config.SpringConfig; import cn.knightzz.entity.Account; import junit.framework.TestCase; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.annotation.Resource; import java.util.List; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {SpringConfig.class}) public class AccountServiceTest extends TestCase { @Resource AccountService accountService; @Test public void testFindAll() { List<Account> accountList = accountService.findAll(); for (Account account : accountList) { System.out.println(account); } } @Test public void testFindById() { Account account = accountService.findById(1); System.out.println(account); } @Test public void testSave() { Account accout = new Account(); accout.setId(3); accout.setName("kiss"); accout.setMoney(300d); accountService.save(accout); } @Test public void testUpdate() { Account accout = new Account(); accout.setId(3); accout.setName("knightzz"); accout.setMoney(400d); accountService.update(accout); } public void testDelete() { } }
2. Spring事务
2.1 Spring事务控制方式
- Spring的事务控制可以分为编程式事务控制和声明式事务控制。
2.1.1 编程式事务
- 开发者直接把事务的代码和业务代码耦合到一起,在实际开发中不用
2.1.2 声明式事务
- 开发者采用配置的方式来实现的事务控制,业务代码与事务代码实现解耦合,使用的AOP思想。
2.2 编程式事务控制对象
2.2.1 不同的Dao层实现对象
- PlatformTransactionManager 是接口类型,不同的 Dao 层技术则有不同的实现类。
- Dao层技术是
jdbcTemplate
或mybatis
时: DataSourceTransactionManager - Dao层技术是
hibernate
时: HibernateTransactionManager - Dao层技术是
JPA
时: JpaTransactionManager
2.2.2 PlatformTransactionManager
-
PlatformTransactionManager接口,是spring的事务管理器,
-
里面提供了我们常用的操作事务的方法
-
常用方法
2.2.3 TransactionDefinition
-
TransactionDefinition接口提供事务的定义信息(事务隔离级别、事务传播行为等等)
-
常用方法
2.2.4 事务隔离级别
-
设置隔离级别,可以解决事务并发产生的问题,如脏读、不可重复读和虚读(幻读)。
-
ISOLATION_DEFAULT
使用数据库默认级别 -
ISOLATION_READ_UNCOMMITTED
读未提交 -
ISOLATION_READ_COMMITTED
读已提交 -
ISOLATION_REPEATABLE_READ
可重复读 -
ISOLATION_SERIALIZABLE
串行化
2.2.5 事务传播行为
-
事务传播行为指的就是当一个业务方法【被】另一个业务方法调用时,应该如何进行事务控制
-
read-only(是否只读):建议查询时设置为只读
-
timeout(超时时间):默认值是-1,没有超时限制。如果有,以秒为单位进行设置
2.2.6 TransactionStatus
-
TransactionStatus 接口提供的是事务具体的运行状态。
-
可以简单的理解三者的关系:事务管理器通过读取事务定义参数进行事务管理,然后会产生一系列的事
务状态。
2.2.7 代码实现
-
SpringConfig
@Bean("transactionManager") public DataSourceTransactionManager getDataSourceTransactionManager(@Autowired DataSource dataSource){ return new DataSourceTransactionManager(dataSource); }
-
Service
@Resource private PlatformTransactionManager transactionManager; /** * 转账操作 * * @param outUser * @param inUser * @param money */ @Override public void transfer(String outUser, String inUser, Double money) { // 创建事务定义对象 DefaultTransactionDefinition def = new DefaultTransactionDefinition(); // 设置是否只读,false支持事务 def.setReadOnly(false); // 设置事务隔离级别,可重复读mysql默认级别 def.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ); // 设置事务传播行为,必须有事务 def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); // 配置事务管理器 TransactionStatus status = transactionManager.getTransaction(def); try { // 转账 accountDao.out(outUser, money); accountDao.in(inUser, money); // 提交事务 transactionManager.commit(status); } catch (Exception e) { e.printStackTrace(); // 回滚事务 transactionManager.rollback(status); } }
2.3 基于XML的声明式事务控制
2.3.1 开发步骤
- 引入tx命名空间
- 事务管理器通知配置
- 事务管理器AOP配置
- 测试事务控制转账业务代码
2.3.2 引入tx命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w2.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/s chema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
</beans>
2.3.3 事务管理器通知配置
<!--事务管理器-->
<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="*"/>
</tx:attributes>
</tx:advice>
2.3.4 事务管理器AOP配置
<!--aop配置-->
<aop:config> <!--切面配置-->
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.lagou.serivce..*.*(..))"> </aop:advisor>
</aop:config>
2.3.5 事务参数的配置
<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="-1" read-only="false"/>
-
name:切点方法名称
-
isolation:事务的隔离级别
-
propogation:事务的传播行为
-
timeout:超时时间
-
read-only:是否只读
2.3.6 CRUD事务常用配置
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
2.4 基于注解的声明式事务控制
2.4.1 基本步骤
- 修改service层,增加事务注解
- 修改spring核心配置文件,开启事务注解支持
2.4.2 开启事务配置
-
SpringConfig :
@EnableTransactionManagement
开启事务@Configuration @ComponentScan("cn.knightzz") @EnableAspectJAutoProxy @EnableTransactionManagement @Import(DataSourceConfig.class) public class SpringConfig {
2.4.3 Service添加注解
-
注意 : 事务注解的代码不要使用try catch 包裹, 否则无法捕获异常, 并进行回滚
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ, timeout = -1, readOnly = false) @Override public void transfer(String outUser, String inUser, Double money) { accountDao.out(outUser, money); int i = 1 / 0; accountDao.in(inUser, money); }