概念及准备
Spring 框架对 JDBC 进行封装,使用 JdbcTemplate
方便实现对数据库操作
-
该模本所需要的 jar 包如下所示:
-
在spring配置文件配置数据库连接池
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="url" value="jdbc:mysql:///test" /> <property name="username" value="root" /> <property name="password" value="root" /> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> </bean>
-
配置
JdbcTemplate对象
,注入DataSource
<!-- JdbcTemplate 对象 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <!--注入 dataSource--> <property name="dataSource" ref="dataSource"></property><!--set方式注入--> </bean>
-
创建service类,创建dao类,在dao注入jdbcTemplate对象
- 配置文件,打开注解的扫描
<!-- 组件扫描 --> <context:component-scan base-package="com.atguigu"></context:component-scan>
- Service类和Dao 类 的编写
@Service public class BookService { //注入 dao @Autowired private BookDao bookDao; } @Repository public class BookDaoImpl implements BookDao { //注入 JdbcTemplate @Autowired private JdbcTemplate jdbcTemplate; }
- 配置文件,打开注解的扫描
JdbcTemplate 操作数据库(添加操作)
对应数据库创建实体类
编写 service 和 dao
在dao进行数据库添加操作时需要调用 JdbcTemplate
对象里面 update方法
实现添加操作
一共两个参数:
⚫ 第一个参数:sql语句
⚫ 第二个参数:可变参数,设置sql语句值
@Repository
public class BookDaoImpl implements BookDao {
//注入 JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
//添加的方法
@Override
public void add(Book book) {
//1 创建 sql 语句
String sql = "insert into t_book values(?,?,?)";
//2 调用方法实现
Object[] args = {book.getUserId(), book.getUsername(),book.getUstatus()};
int update = jdbcTemplate.update(sql,args);
System.out.println(update);
}
}
测试结果如下:
JdbcTemplate 操作数据库(修改和删除操作)
- 修改操作:
@Override public void updateBook(Book book) { String sql = "update t_book set username=?,ustatus=? where user_id=?"; Object[] args = {book.getUsername(), book.getUstatus(),book.getUserId()}; int update = jdbcTemplate.update(sql, args); System.out.println(update); }
- 删除操作:
//2、删除 @Override public void delete(String id) { String sql = "delete from t_book where user_id=?"; int update = jdbcTemplate.update(sql, id); System.out.println(update); }
- 使用JdbcTemplate 模板所实现的 “增删改” 都是调用了同一个 “update” 方法
JdbcTemplate 操作数据库(查询返回某个值)
//查询表记录数
@Override
public int selectCount() {
String sql = "select count(*) from t_book";
//queryForObject方法中:第一个参数代表--sql语句;第二个参数代表--返回类型class
Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
return count;
}
JdbcTemplate 操作数据库(查询返回对象)
//查询返回对象
@Override
public Book findBookInfo(String id) {
String sql = "select * from t_book where user_id=?";
//调用方法
/*
queryForObject方法中:
第一个参数:sql语句
第二个参数:RowMapper 是接口,针对返回不同类型数据,使用这个接口里面 实现类 完成数据封装
第三个参数:sql 语句值
*/
Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book>(Book.class), id);
return book;
}
JdbcTemplate 操作数据库(查询返回集合)
//查询返回对象
@Override
public Book findBookInfo(String id) {
String sql = "select * from t_book where user_id=?";
//调用方法
/*
queryForObject方法中:
第一个参数:sql语句
第二个参数:RowMapper 是接口,针对返回不同类型数据,使用这个接口里面 实现类 完成数据封装
第三个参数:sql 语句值
*/
Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book>(Book.class), id);
return book;
}
JdbcTemplate 操作数据库(批量操作)
批量操作:操作表里面多条记录
- JdbcTemplate 实现批量添加操作
- ⚫ 有两个参数
⚫ 第一个参数:sql语句
⚫ 第二个参数:List集合,添加多条记录数据
批量添加操作
代码如下:
//批量添加
@Override
public void batchAddBook(List<Object[]> batchArgs) {
String sql = "insert into t_book values(?,?,?)";
//batchUpdate方法 第一个参数:sql语句 第二个参数:List集合,添加多条记录数据
int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
System.out.println(Arrays.toString(ints));
}
测试代码如下:
//批量添加测试
List<Object[]> batchArgs = new ArrayList<>();
Object[] o1 = {"3","java","a"};
Object[] o2 = {"4","c++","b"};
Object[] o3 = {"5","MySQL","c"};
batchArgs.add(o1);
batchArgs.add(o2);
batchArgs.add(o3);
//调用批量添加
bookService.batchAdd(batchArgs);
批量修改操作
//批量修改
@Override public void batchUpdateBook(List<Object[]> batchArgs) {
String sql = "update t_book set username=?,ustatus=? where user_id=?";
int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
System.out.println(Arrays.toString(ints
}
//批量修改测试代码
List<Object[]> batchArgs = new ArrayList<>();
Object[] o1 = {"java0909","a3","3"};
Object[] o2 = {"c++1010","b4","4"};
Object[] o3 = {"MySQL1111","c5","5"};
batchArgs.add(o1);
batchArgs.add(o2);
batchArgs.add(o3);
//调用方法实现批量修改
bookService.batchUpdate(batchArgs);
批量删除操作
//批量删除
@Override public void batchDeleteBook(List<Object[]> batchArgs) {
String sql = "delete from t_book where user_id=?";
int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
System.out.println(Arrays.toString(ints));
}
//批量删除 测试
List<Object[]> batchArgs = new ArrayList<>();
Object[] o1 = {"3"};
Object[] o2 = {"4"};
batchArgs.add(o1);
batchArgs.add(o2);
//调用方法实现批量删除
bookService.batchDelete(batchArgs);
事务操作的提出场景
事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败,所有操作都失败。
典型场景:银行转账(下面操作就为一个事务操作)
- lucy 转账100元 给mary
- lucy少100,mary多100
因此事务存在四个特性(ACID)
- 原子性
- 一致性
- 隔离性
- 持久性
转账场景模拟:事务提出的场景
- 对数据库的操作应该交给 dao层,即增加账户的余额或者减少账户余额
- 对这些方法的整合利用应当交给 service层,如下
-
创建数据库表,添加记录
-
创建
service
,搭建dao
,完成对象创建和注入关系
在 service 中注入dao
,在 dao 中注入JdbcTemplate
,在 JdbcTemplate 中注入DataSource
@Service public class UserService { //注入dao @Autowired private UserDao userDao; } @Repository public class UserDaoImpl implements UserDao { @Autowired private JdbcTemplate jdbcTemplate; }
-
在dao创建两个方法:增加钱和减少钱的方法,
@Repository public class UserDaoImpl implements UserDao { @Autowired private JdbcTemplate jdbcTemplate; //lucy转账100给mary //少钱 @Override public void reduceMoney() { String sql = "update t_account set money=money-? where username=?"; jdbcTemplate.update(sql,100,"lucy"); } //多钱 @Override public void addMoney() { String sql = "update t_account set money=money+? where username=?"; jdbcTemplate.update(sql,100,"mary"); } }
-
在service创建整合的方法(转账的方法)
@Service public class UserService { //注入dao @Autowired private UserDao userDao; //转账的方法 public void accountMoney() { //lucy少100 userDao.reduceMoney(); //mary多100 userDao.addMoney(); } }
上面代码,如果正常执行没有问题的,但是如果代码执行过程中出现异常,有问题
上满问题解决的方式:利用事务进行解决
Spring 事务管理介绍
1、事务添加到 JavaEE
三层结构里面 Service层
(业务逻辑层)
2、在Spring进行事务管理操作
(1)有两种方式 :编程式事务管理 和 声明式事务管理(使用)
3、声明式事务管理
(1)基于注解方式(使用)
(2)基于xml配置文件方式
4、在Spring进行声明式事务管理,底层使用AOP原理
Spring事务管理API提供了一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类
注解声明式事务管理器
环境配置
-
在spring配置文件中配置事务管理器
<!--创建事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--注入数据源--> <property name="dataSource" ref="dataSource"></property> </bean>
-
在 Spring 配置文件中开启事务注解
在spring配置文件引入名称空间xmlns:tx="http://www.springframework.org/schema/tx"
<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: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/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/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">
开启事务注解:
<!--开启事务注解--> <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
-
在
service类
上面(或者service类里面方法上面)添加 事务注解:
@Transactional
,这个注解添加到类上面,也可以添加方法上面- 如果把这个注解添加类上面,这个类里面所有的方法都添加事务
- 如果把这个注解添加方法上面,为这个方法添加事务
@Service @Transactional public class UserService {}
参数配置
在 service类
上面添加注解 @Transactional
,在这个注解里面可以配置事务的相关参数
propagation:事务传播行为
propagation 主要为那些事务中套事务的场景(即事务的传播行为)指定运行策略,有7种可选策略,如下所示:
ioslation:事务隔离级别
由于事务存在隔离性,因此很容易产生三种可能出现的读问题:脏读、不可重复读、虚(幻)读。
- 脏读:一个未提交事务读取到另一个未提交事务的数据
- 不可重复读:一个未提交事务读取到另一提交事务修改数据
- 虚读: 一个未提交事务读取到另一提交事务添加数据
上面这三种隔离问题的解决防范为:设置事务的隔离级别,解决读问题
timeout:超时时间
- (1)事务需要在一定时间内进行提交,如果不提交则进行回滚
- (2)默认值是
-1
,设置时间以秒单位进行计算
readOnly:是否只读
读:查询操作,写:添加修改删除操作
- (2)readOnly默认值false,表示可以查询,可以添加修改删除操作
- (3)设置readOnly值是true,设置成true之后,只能查询
rollbackFor:回滚
(1)设置出现哪些异常进行事务回滚
noRollbackFor:不回滚
(1)设置出现哪些异常不进行事务回滚
xml 声明式事务管理
在 spring 配置文件中进行配置
- 第一步 配置事务管理器
- 第二步 配置通知
- 第三步 配置切入点和切面
配置文件如下:
<!--1 创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--2 配置通知-->
<tx:advice id="txadvice">
<!--配置事务参数-->
<tx:attributes>
<!--指定哪种规则的方法上面添加事务-->
<tx:method name="accountMoney" propagation="REQUIRED"/>
<!--<tx:method name="account*"/>-->
</tx:attributes>
</tx:advice>
<!--3 配置切入点和切面-->
<aop:config>
<!--配置切入点-->
<aop:pointcut id="pt" expression="execution(* com.atguigu.spring5.service.UserService.*(..))"/>
<!--配置切面-->
<aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
</aop:config>
完全注解声明式管理
- 创建配置类,使用配置类替代 xml配置文件
@Configuration
//配置类
@ComponentScan(basePackages = "com.atguigu")
//组件扫描
@EnableTransactionManagement
//开启事务
public class TxConfig {
//创建数据库连接池
@Bean
public DruidDataSource getDruidDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///user_db");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
//创建JdbcTemplate对象
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
//到ioc容器中根据类型找到dataSource
JdbcTemplate jdbcTemplate = new JdbcTemplate();
//注入dataSource
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
//创建事务管理器
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}