目录
1.JdbcTemplate
JdbcTemplate是Spring的一款用于简化Dao代码的类库,它底层封装了JDBC技术。
核心对象
JdbcTemplate jdbcTemplate = new JdbcTemplate(DataSource dataSource);
核心方法
int update(); 执行增、删、改语句
List<T> query(); 查询多个
T queryForObject(); 查询一个
new BeanPropertyRowMapper<>(); 实现ORM映射封装
代码演示
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.9</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
</dependencies>
测试类
public class AccountServiceTest {
@Test
public void save() {
Account account = new Account();
account.setName("jiujiu");
account.setMoney(1000);
new AccountDaoImpl().save(account);
}
@Test
public void findById() {
Account byId = new AccountDaoImpl().findById(1);
System.out.println(byId);
}
@Test
public void findAll() {
List<Account> all = new AccountDaoImpl().findAll();
System.out.println(all);
}
}
实体类
@Data
public class Account {
private int id;
private String name;
private double money;
}
dao接口
public interface AccountDao{
void save(Account account);
Account findById(int id);
List<Account> findAll();
}
dao实现类
public class AccountDaoImpl implements AccountDao {
@Override
public void save(Account account) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource());
String sql = "insert into account (name,money) values (?,?)";
jdbcTemplate.update(sql,account.getName(),account.getMoney());
}
@Override
public Account findById(int id) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource());
String sql = "select * from account where id = ?";
return jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<>(Account.class),id);
}
@Override
public List<Account> findAll() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource());
String sql = "select * from account";
return jdbcTemplate.query(sql,new BeanPropertyRowMapper<>(Account.class));
}
}
2.Spring整合JdbcTemplate
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.study"/>
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="accountDao" class="com.study.dao.Impl.AccountDaoImpl"/>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="ds" name="dataSource"/>
</bean>
<bean id="ds" 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>
</beans>
测试类
@RunWith(SpringRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class AccountServiceTest {
@Autowired
AccountDao accountDao;
@Test
public void save() {
Account account = new Account();
account.setName("jiujiu");
account.setMoney(1000);
accountDao.save(account);
}
@Test
public void findById() {
Account byId = accountDao.findById(1);
System.out.println(byId);
}
@Test
public void findAll() {
List<Account> all = accountDao.findAll();
System.out.println(all);
}
}
dao接口
public interface AccountDao{
void save(Account account);
Account findById(int id);
List<Account> findAll();
}
dao实现类
@Repository
public class AccountDaoImpl implements AccountDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void save(Account account) {
// JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource());
String sql = "insert into account (name,money) values (?,?)";
jdbcTemplate.update(sql,account.getName(),account.getMoney());
}
@Override
public Account findById(int id) {
// JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource());
String sql = "select * from account where id = ?";
return jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<>(Account.class),id);
}
@Override
public List<Account> findAll() {
// JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource());
String sql = "select * from account";
return jdbcTemplate.query(sql,new BeanPropertyRowMapper<>(Account.class));
}
}
3.Spring的事务
spring的事务分成编程式事务和声明式事务。
3.1PlatformTransactionManager
spring事务管理器的顶级接口,里面提供了我们常用的操作事务的方法。
TransactionStatus getTransaction(TransactionDefinition definition);
功能:获取事务的状态信息void commit(TransactionStatus status);
功能:提交事务void rollback(TransactionStatus status);
功能:回滚事务
3.2TransactionDefinition
spring事务定义参数的接口,比如定义:事务隔离级别、事务传播行为等等。
3.2.1事务的隔离级别
ISOLATION_DEFAULT 使用数据库默认级别
mysql:默认是 ISOLATION_REPEATABLE_READ
Oracle:默认是 ISOLATION_READ_COMMITTED
ISOLATION_READ_UNCOMMITTED 读未提交,不解决问题
ISOLATION_READ_COMMITTED 读已提交,解决了脏读
ISOLATION_REPEATABLE_READ 可重复读,解决了脏读、不可重复读
ISOLATION_SERIALIZABLE 串行化,解决了脏读、不可重复读、幻读
3.2.2事务的传播行为
事务传播行为指的就是当一个业务方法【被】另一个业务方法调用时,应该如何进行事务控制。
REQUIRED 必须
如果当前没有事务,就新建一个事务,如果已经存在一个事务,加入到这个事务中。
SUPPORTS 支持
支持当前事务,如果当前没有事务,就以非事务方式执行。
MANDATORY 强制
使用当前的事务,如果当前没有事务,就抛出异常。
REQUERS_NEW 新建
新建事务,如果当前在事务中,把当前事务挂起。NOT_SUPPORTED 不支持
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
NEVER 从不
以非事务方式运行,如果当前存在事务,抛出异常。
NESTED 嵌套
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作。
3.2.3是否只读
read-only=false 只读事务(增 删 改不能使用,只能查询使用)
3.2.4超时时间
timeout 默认值是-1,没有超时限制。如果有,以秒为单位进行设置。
3.3TransactionStatus
获取spring当前事务运行的状态。
可以简单的理解三者的关系:事务管理器通过读取事务定义参数进行事务管理,然后会产生一系列的事务状态。
3.2编程式事务
编程式事务将业务代码和事务代码书写在一起。
添加依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.study"/>
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="ds" name="dataSource"/>
</bean>
<bean id="ds" 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>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="ds"/>
</bean>
</beans>
测试类
@RunWith(SpringRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class AccountServiceTest {
@Autowired
AccountService accountService;
@Test
public void transfer(){
accountService.transfer("tom","jerry",100D);
}
}
service接口
public interface AccountService {
void transfer(String inName,String outName,Double money);
}
service实现类
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private DataSourceTransactionManager transactionManager;
@Autowired
private AccountDao accountDao;
@Override
public void transfer(String inName, String outName, Double money) {
DefaultTransactionDefinition dtd = new DefaultTransactionDefinition();
//设置事务的隔离级别
dtd.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
//设置事务的传播行为
dtd.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
//设置是否只读
dtd.setReadOnly(false);
//设置超时时间
dtd.setTimeout(3);
// 对事务管理器进行配置
TransactionStatus status = transactionManager.getTransaction(dtd);
try {
accountDao.outMoney(outName,money);
int i = 1/0;
accountDao.inMoney(inName,money);
transactionManager.commit(status);
} catch (Exception e) {
e.printStackTrace();
transactionManager.rollback(status);
}
}
}
dao接口
public interface AccountDao{
void outMoney(String outName,Double money);
}
dao实现类
@Repository
public class AccountDaoImpl implements AccountDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void outMoney(String outName, Double money) {
String sql = "update account set money = money - ? where name = ?";
jdbcTemplate.update(sql,money,outName);
}
}
3.3声明式事务
spring提供了声明式事务,已经封装好了。底层原理就是SpringAOP。
主要步骤:
1.将事务管理器DataSourceTransactionManager交个IOC容器。
2.声明事务管理器DataSourceTransactionManager是一个切面类。
3.配置切面。在配置切面时使用spring提供好的advisor标签。
3.3.1xml方式
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
</dependency>
</dependencies>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="ds" 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>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg name="dataSource" ref="ds"/>
</bean>
<bean id="accountDao" class="com.study.dao.impl.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="accountService" class="com.study.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
<!--配置spring的事务管理器需要以下步骤
1.将事务管理器交给IOC容器
2.声明事务管理器是一个通知类
3.给service层配置切面
-->
<!--将事务管理器交给IOC-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="ds"/>
</bean>
<!--声明DataSourceTransactionManager是一个通知类-->
<tx:advice id="myTxAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!--配置切面-->
<aop:config>
<!--spring专门用于事务管理的的标签 advisor-->
<aop:advisor advice-ref="myTxAdvice" pointcut="execution(* com.study.service..*.*(..))"/>
</aop:config>
</beans>
测试类
@RunWith(SpringRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class AccountServiceImplTest {
@Autowired
private AccountService accountService;
@Test
public void transfer() {
accountService.transfer("tom","jerry",100D);
}
}
service接口
public interface AccountService {
void transfer(String inName, String outName, Double money);
}
service实现类
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(String inName, String outName, Double money) {
accountDao.outMoney(outName,money);
int i= 1/0;//模拟异常
accountDao.inMoney(inName,money);
}
}
dao接口
public interface AccountDao {
void inMoney(String name, Double money);
void outMoney(String name, Double money);
}
dao实现类
public class AccountDaoImpl implements AccountDao {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public void inMoney(String name, Double money) {
String sql = "update account set money = money - ? where name = ?";
jdbcTemplate.update(sql,money,name);
}
@Override
public void outMoney(String name, Double money) {
String sql = "update account set money = money - ? where name = ?";
jdbcTemplate.update(sql,money,name);
}
}
xml配置通知类解释
<!--声明DataSourceTransactionManager是一个通知类-->
<tx:advice id="myTxAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--
name:表示方法名称,*可以匹配任意字符。
propagation:定义事务的传播行为。
isolation:事务的隔离级别。
read-only:是否只读。
timeout:事务失效时间。
-->
<tx:method name="save*" propagation="REQUIRED" isolation="DEFAULT" read-only="false" timeout="-1"/>
<tx:method name="update*" propagation="REQUIRED" isolation="DEFAULT" read-only="false" timeout="-1"/>
<tx:method name="delete*" propagation="REQUIRED" isolation="DEFAULT" read-only="false" timeout="-1"/>
<tx:method name="query*" propagation="SUPPORTS" isolation="DEFAULT" read-only="true" timeout="-1"/>
<tx:method name="*" propagation="REQUIRED" isolation="DEFAULT" read-only="false" timeout="-1"/>
</tx:attributes>
</tx:advice>
3.3.2注解方式
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="ds" 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>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg name="dataSource" ref="ds"/>
</bean>
<bean id="accountDao" class="com.study.dao.impl.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="accountService" class="com.study.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
<!--配置spring的事务管理器需要以下步骤
1.将事务管理器交给IOC容器
2.声明事务管理器是一个通知类
3.给service层配置切面
-->
<!--将事务管理器交给IOC-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="ds"/>
</bean>
<!--开启spring事务注解的支持-->
<tx:annotation-driven transaction-manager="transactionManager"/>
</aop:config>-->
</beans>
service实现类
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
@Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRED,readOnly = false,timeout = -1)
public void transfer(String inName, String outName, Double money) {
accountDao.outMoney(outName,money);
int i= 1/0;//模拟异常
accountDao.inMoney(inName,money);
}
}
3.3.3纯注解
applicationContext.xml可以删掉了
SpringConfig(配置类)
@Configuration//声明此类是配置类
@Component//加入IOC容器
@ComponentScan(value = "com.study")//包扫描,扫描spring注解
@PropertySource("classpath:jdbc.properties")//引入外部文件
@EnableTransactionManagement//开启事务的注解支持
public class SpringConfig {
@Value("${jdbc.driver}")//从外部文件中获取值
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean//加入IOC容器
public DataSource createDatasource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
return ds;
}
@Bean
public JdbcTemplate createJdbcTemplate(@Autowired DataSource ds){
return new JdbcTemplate(ds);
}
@Bean
public DataSourceTransactionManager createTransactionManager(@Autowired DataSource ds){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(ds);
return dataSourceTransactionManager;
}
}
测试类
@RunWith(SpringRunner.class)//以spring的方式启动
//@ContextConfiguration(locations = "classpath:applicationContext.xml")
@ContextConfiguration(classes = SpringConfig.class)//使用配置类的方式启动
public class AccountServiceImplTest {
@Autowired//注入
private AccountService accountService;
@Test
public void transfer() {
accountService.transfer("tom","jerry",100D);
}
}
service接口
public interface AccountService {
void transfer(String inName, String outName, Double money);
}
service实现类
@Service//加入IOC容器
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
/*public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}*/
@Override
@Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRED,readOnly = false,timeout = -1)//开启事务
public void transfer(String inName, String outName, Double money) {
accountDao.outMoney(outName,money);
int i= 1/0;//模拟异常
accountDao.inMoney(inName,money);
}
}
dao接口
public interface AccountDao {
void inMoney(String name, Double money);
void outMoney(String name, Double money);
}
dao实现类
@Repository//加入IOC
public class AccountDaoImpl implements AccountDao {
@Autowired
private JdbcTemplate jdbcTemplate;
/*public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}*/
@Override
public void inMoney(String name, Double money) {
String sql = "update account set money = money - ? where name = ?";
jdbcTemplate.update(sql,money,name);
}
@Override
public void outMoney(String name, Double money) {
String sql = "update account set money = money - ? where name = ?";
jdbcTemplate.update(sql,money,name);
}
}