4. JdbcTemplate
4.1 概念
JdbcTemplate是Spring框架对JDBC进行了封装,便于数据库操作。
4.2 使用
1. 引入依赖
spring的依赖:spring-jdbc、spring-tx、spring-orm
数据库的依赖:mysql-connector-java druid
2. 在spring配置文件中配置数据库连接池和JdbcTemplate对象
database.properties文件
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/sms?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
jdbc.username=root
jdbc.password=root
spring配置文件
<?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"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.spring.demo.jdbc" />
<context:property-placeholder location="database.properties" />
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<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">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
3. 创建service类,dao类,在dao中注入JdbcTemplate对象,在service类中注入dao对象。
package com.spring.demo.jdbc.service;
public interface StudentService {
String queryUserNameById(int id);
}
package com.spring.demo.jdbc.service;
import com.spring.demo.jdbc.dao.StudentDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentDao dao;
@Override
public String queryUserNameById(int id) {
return dao.findUserNameById(id);
}
}
package com.spring.demo.jdbc.dao;
public interface StudentDao {
String findUserNameById(int id);
}
package com.spring.demo.jdbc.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class StudentDaoImpl implements StudentDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public String findUserNameById(int id) {
String sql = "select username from student where sid = " + id;
return jdbcTemplate.queryForObject(sql, String.class);
}
}
4. 测试
@Test
public void testJdbcTemplate() {
ClassPathXmlApplicationContext applicationContext
= new ClassPathXmlApplicationContext("classpath:spring_jdbc.xml");
StudentServiceImpl studentServiceImpl =
applicationContext.getBean("studentServiceImpl", StudentServiceImpl.class);
String userName = studentServiceImpl.queryUserNameById(2);
System.out.println(userName);
}
5. 事务
5.1 概念
1. 什么是事务
数据库操作的最基本单元,逻辑上的一组操作,要么都成功,要么都失败。典型的场景:银行转账。
2. 事务特性(ACID)
原子性、一致性、隔离性、持久性。
5.2 搭建事务操作场景(转账)
1. 创建表,用于存储用户的账户余额
2. 创建service,dao,完成对象的创建和注入关系
package com.spring.demo.tx.service;
public interface AccountService {
void transfer();
}
package com.spring.demo.tx.service;
import com.spring.demo.tx.dao.AccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
public void transfer() {
accountDao.modifyMoney("小明", - 10);
int i = 1 / 0;
accountDao.modifyMoney("小红", 10);
}
}
package com.spring.demo.tx.dao;
public interface AccountDao {
void modifyMoney(String username, int delta);
}
package com.spring.demo.tx.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class AccountDaoImpl implements AccountDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void modifyMoney(String username, int delta) {
String sql = "update account set money = money + " + delta + " where username = '" + username + "'";
jdbcTemplate.update(sql);
}
}
3. 转账过程人为加上异常
4.测试
@Test
public void testTx() {
ClassPathXmlApplicationContext applicationContext
= new ClassPathXmlApplicationContext("classpath:spring_jdbc.xml");
AccountServiceImpl accountServiceImpl =
applicationContext.getBean("accountServiceImpl", AccountServiceImpl.class);
accountServiceImpl.transfer();
}
5.测试结果
5.3 Spring中的事务操作
在5.2的场景当中,两次数据库操作中间出现了异常,导致最后的结果出现问题。因此需要,对transfer()方法添加事务,让两次数据库操作处于同一个事务当中,要么同时成功,要么同时失败。
1. 事务管理方式
编程式(写代码)和声明式(配置)。
2. 原理
在spring中进行事务管理,底层使用AOP实现。
3. 基于注解的声明式事务管理实现步骤
(1)配置事务管理器 (JdbcTemplate使用DataSourceTransactionManager)
(2)引入命名空间tx
(3)开启事务注解
(4)在service类上面(或者其中的某个方法上)添加事务注解@Transactional
@Transactional的属性:
propagation:事务传播行为。对事务方法(会对数据做更改的方法)进行相互调用时,如何管理事务。
isolation:事务隔离等级。
脏读:一个事务读取到了另外一个事务未提交的数据
幻读:前后两次读取的数据条数不一致,一个未提交的事务读取了另一个事务添加的数据。
不可重复读:前后两次读取的数据内容不一致,一个未提交的事务读取了另一个事务修改的数据。
timeout:超时时间。事务需要在一定的时间内提交,如果不提交就进行回滚。
readOnly:是否只读。设置成true只能对数据进行查询操作。
rollbackFor:回滚。设置出现哪些异常进行回滚。
norollbackFor:不回滚。设置出现哪些异常不进行回滚。
(5)测试
转账失败,数据库并未出现异常
4. 基于xml配置文件的声明式事务管理实现步骤(略)
5. 完全注解实现声明式事务管理
(1)创建配置类替代xml配置文件。
package com.spring.demo.tx.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
// 开启组件扫描
@ComponentScan(basePackages = {"com.spring.demo.tx"})
// 开启事务注解扫描
@EnableTransactionManagement
public class TxConfigClass {
/**
* 向容器中注入数据源对象
*
* @return 数据源对象
*/
@Bean
public DruidDataSource getDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/sms?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC ");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
/**
* 向容器中注入JdbcTemplate对象
*
* @param dataSource 数据源
* @return JdbcTemplate
*/
@Bean
public JdbcTemplate getJdbcTemplate(DruidDataSource dataSource) {
return new JdbcTemplate(dataSource);
}
/**
* 向容器中注入DataSourceTransactionManager对象
*
* @param dataSource 数据源
* @return DataSourceTransactionManager对象
*/
@Bean
public DataSourceTransactionManager getTransactionManager(DruidDataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
(2)测试
生效