Spring框架-JdbcTemplate
1.概念和准备
1.1 什么是 JdbcTemplate
- Spring 框架对
JDBC
进行封装,使用JdbcTemplate
方便实现对数据库操作
1.2 准备工作
引入依赖:
- `spring-jdbc-xxx.jar``
- ``spring-orm-5.2.6.xxx.jar`
- spring-tx-5.2.6.xxx.jar
- ``druid-xxx.jar`
- mysql-connector-java-xxx.jar`
在 spring 配置文件配置数据库连接池:
<!--引入外部属性文件--> <context:property-placeholder location="classpath:jdbc.properties"/> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${prop.driverClassName}"></property><property name="url" value="${prop.url}"></property><property name="username" value="${prop.username}"></property><property name="password" value="${prop.password}"></property> </bean>
- 配置 JdbcTemplate 对象,注入 DataSource:
<!-- JdbcTemplate 对象 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><!--注入 dataSource,因为JdbcTemplate类的有参构造方法中需要参数DataSource,而DataSource是在其父类的一个属性,所以这里是对其父类的一个set注入,不是说直接传入DataSource作为JdbcTemplate类的有参构造方法中的参数--><property name="dataSource" ref="dataSource"></property> </bean>
- 创建 service 类和dao 类,在service注入dao对象以及在dao注入 JdbcTemplate 对象:
<!--注意开启组件扫描--> <context:component-scan base-package="com.psj"></context:component-scan>
@Service public class BookService {@Autowiredprivate BookDao bookDao; } @Repository public class BookDaoImpl implements BookDao {@Autowiredprivate JdbcTemplate jdbcTemplate; }
2.JdbcTemplate 操作数据库
- 对应数据库的表字段创建实体类:
public class Book {private String userId;private String username;private String usstatus;public String getUserId() {return userId;}// 剩余的set和get方法
- 编写 service 和 dao:
@Service public class BookService {@Autowiredprivate BookDao bookDao;public void addBook(Book book){bookDao.add(book);}// 查询表记录数目public int findCount(){return bookDao.selectCount();}// 查询书本public Book findOne(String id){return bookDao.findBookInfo(id);}// 查询所有书本集合public List<Book> findAll(){return bookDao.findAllBook();}// 批量添加书本public void batchAdd(List<Object[]> batchArgs){bookDao.batchAddBook(batchArgs);} } @Repository public class BookDaoImpl implements BookDao {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic void add(Book book) {String sql = "insert into book values(?,?,?)";Object[] args = {book.getUserId(), book.getUsername(), book.getUsstatus()};int update = jdbcTemplate.update(sql, args);System.out.println(update); // 表示成功添加的行数}@Overridepublic int selectCount() {String sql = "select count(*) from book";// 查询返回某个值// 第二个参数为返回的类型int count = jdbcTemplate.queryForObject(sql, Integer.class);return count;}@Overridepublic Book findBookInfo(String id) {String sql = "select * from book where user_id = ?";// 查询返回某个对象// 第二个参数为RowMapper,它是接口,针对返回的不同类型数据,使用这个接口里面完成类的数据封装Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book>(Book.class), id);return book;}@Overridepublic List<Book> findAllBook() {String sql = "select * from book";List<Book> bookList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Book>(Book.class));return bookList;}@Overridepublic void batchAddBook(List<Object[]> batchArgs) {String sql = "insert into book values(?,?,?)";// 将List数组中的每一组元素添加给占位符int[] update = jdbcTemplate.batchUpdate(sql, batchArgs);System.out.println(update);} } // 测试 ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); BookService bookService = context.getBean("bookService", BookService.class); 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);
3.事务操作
3.1 事务概念和特点
- 事务是数据库操作最基本单元,逻辑上的一组操作(比如A转账给B100元,A要少100元,B同时要多100元)要么都成功,如果有一个失败所有操作都失败
- 事务四个特性(
ACID
):
- 原子性:要么都成功,要么都失败
- 一致性:操作前和操作后的总量不变
- 隔离性:多事务操作的时候它们之间不会产生影响
- 持久性:事务提交后表中数据发生变化
3.2 异常场景
@Service public class UserService {@Autowiredprivate UserDao userDao;public void accountMoney(){userDao.reduceMoney(); // psw少100int i = 1 / 0; // 模拟异常userDao.addMoney(); // psj多100} } @Repository public class UserDaoImpl implements UserDao {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic void addMoney() {String sql = "update account set money=money+? where username=?";jdbcTemplate.update(sql, 100, "psj"); // psj多100}@Overridepublic void reduceMoney() {String sql = "update account set money=money-? where username=?";jdbcTemplate.update(sql, 100, "psw"); // psw少100} } // 正常执行userService.accountMoney()后数据库的变化是没有问题的,但是如果代码执行过程中出现异常。但此时出现除数异常,数据库中psw少100但是psj没有多100。需要使用事务进行解决
3.3 事务管理
- 编程式事务管理:会有很多冗余的代码
public void accountMoney() {try {// 1.开启事务// 2.业务操作userDao.reduceMoney(); // psw少100int i = 1 / 0; // 模拟异常userDao.addMoney(); // psj多100// 3.没有发生异常就提交事务} catch (Exception e) {// 4.出现异常则事务回滚(回到操作之前的状态)} }
声明式事务管理:底层使用AOP
- 基于注解:
// 需要先引入名称空间 <!--创建事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!--注入数据源--><property name="dataSource" ref="dataSource"></property> </bean> <!--开启事务注解--> <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
@Service // 可以加在类上(类中所有方法都添加事务),也可以加在方法上 @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ) public class UserService {@Autowiredprivate UserDao userDao;public void accountMoney() {// 注意把try-catch删除,不删除不会执行回滚操作,直接被catchuserDao.reduceMoney(); // psw少100int i = 1 / 0; // 模拟异常userDao.addMoney(); // psj多100} } // 此时再次执行accountMoney(),数据库中的两个人的money值都不会变化
- 基于XML:
<!--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*"/>--> // 表示为account开头的方法添加事务</tx:attributes> </tx:advice> <!--3.配置切入点和切面--> <aop:config><!--配置切入点--><aop:pointcut id="pt" expression="execution(* com.psj.JDBCTemplate.service.UserService.* (..))"/><!--配置切面--><aop:advisor advice-ref="txadvice" pointcut-ref="pt"/> </aop:config>
- 完全注解:
@Configuration // 表示该类是配置类 @ComponentScan(basePackages = "com.psj.JDBCTemplate") // 开启组件扫描 @EnableTransactionManagement // 开启事务 public class TxConfig {// 创建数据库连接池@Beanpublic DruidDataSource getDruidDataSource(){DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName("com.mysql.jdbc.Driver");dataSource.setUrl("jdbc:mysql://localhost:3306/jdbc?serverTimezone=UTC");dataSource.setUsername("root");dataSource.setPassword("xxxx");return dataSource;}@Bean// 创建JDBCTemplate对象public JdbcTemplate getJdbcTemplate(DataSource dataSource){JdbcTemplate jdbcTemplate = new JdbcTemplate();// 注入dataSource:IOC容器中会自动去找DataSource类型的注入对象jdbcTemplate.setDataSource(dataSource);return jdbcTemplate;}@Beanpublic DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();// 注入dataSource:IOC容器中会自动去找DataSource类型的注入对象dataSourceTransactionManager.setDataSource(dataSource);return dataSourceTransactionManager;} }
// 对应上述代码 <!--开启组件扫描--> <context:component-scan base-package="com.psj.JDBCTemplate"></context:component-scan><!--引入外部属性文件--> <context:property-placeholder location="classpath:jdbc.properties"/> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${prop.driverClassName}"></property><property name="url" value="${prop.url}"></property><property name="username" value="${prop.username}"></property><property name="password" value="${prop.password}"></property> </bean> <!-- JdbcTemplate 对象 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><!--注入 dataSource,因为JdbcTemplate类中有参构造就是传入该参数--><property name="dataSource" ref="dataSource"></property> </bean> <!--创建事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!--注入数据源--><property name="dataSource" ref="dataSource"></property> </bean> <!--开启事务注解--> <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
tips:
- 事务添加到Service层中(理论上可以加到三层中的任意一层)
- Spring 事务管理是提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类,如下图中对
Hibernate
等都有实现类
@Transactional
中的参数介绍:
propagation
:事务传播行为(即多事务方法直接进行调用,则该过程事务是如何进行管理的),比如在已经加了事务注解的add
方法中调用没加事务注解的update
方法,事务该如何管理(传播行为有7种,以下两种最常见)
REQUIRED
:默认值。如果add
方法有事务,被调用的update
方法会使用add方法的事务;如果add
方法没有事务的话,update
方法就使用自己的事务REQUIRED_NEW
:无论add
方法是否有事务,update
方法都创建新的事务
ioslation
:事务隔离级别。事务的隔离性保证多事务操作(并发操作)之间不会产生影响,不考虑隔离性产生很多问题(三个读的问题)
- 脏读:一个未提交事务读取到另一个未提交事务的数据(事务未提交就可以回滚)。假如
psj
开启事务A,psw
开启事务B,此时psw
将一条数据中的money
由100改为200,此时psj
读到的数据是200,但是如果psw
开启事务回滚,数据又变回原来的100,和psj
读到的数据不一致- 不可重复读:一个未提交事务读取到另一提交事务修改的数据。假如
psj
开启事务A,psw
开启事务B,此时psw
将一条数据中的money
由100改为200,并且立刻提交事务。此时psj
还没提交事务,但是却读到的数据变为200,正常情况应该要等psj
提交完事务数据才会改变(为什么加不可重复读?假设psj
原来读到100,可是在psw
修改为200并提交事务后就再也读不到100这个值了)- 虚读(幻读):一个未提交事务读取到另一提交事务添加的数据,和不可重复读类似,就是
psw
添加数据并提交事务后,psj
能读到该数据(相当于于psj
第一查询有10条数据,等第二次查询就变成12条了)
timeout
:超时时间。事务需要在一定时间内进行提交,如果不提交则进行回滚(默认值是 -1)
readOnly
:是否只读。默认值 false,表示可以查询也可以添加修改删除操作
rollbackFor
:回滚。设置出现哪些异常时进行事务回滚
noRollbackFor
:不回滚。设置出现哪些异常时不进行事务回滚事务方法:对数据库数据进行变化的操作
Spring框架-JdbcTemplate相关推荐
- Spring框架 JdbcTemplate类 @Junit单元测试,可以让方法独立执行 如:@Test
1 package cn.zmh.PingCe; 2 3 import org.junit.Test; 4 import org.springframework.jdbc.core.BeanPrope ...
- spring框架(五)之JdbcTemplate基本使用
数据准备 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http:/ ...
- Spring框架对JDBC的简单封装。提供了一个JDBCTemplate对象简化JDBC的开发
Spring JDBC * Spring框架对JDBC的简单封装.提供了一个JDBCTemplate对象简化JDBC的开发 * 步骤: 1. 导入jar包 ...
- Spring框架(下)JdbcTemplate、声明式事务管理
Spring框架(下)JdbcTemplate.声明式事务管理 (一)使用JdbcTemplate 1.概述 为了使JDBC更加易于使用,Spring在JDBC API上定义了一个抽象层,以此建立一个 ...
- Spring框架针对dao层的jdbcTemplate操作crud之query查询数据操作
查询目标是完成3个功能: (1)查询表,返回某一个值.例如查询表中记录的条数,返回一个int类型数据 (2)查询表,返回结果为某一个对象. (3)查询表,返回结果为某一个泛型的list集合. 一.查询 ...
- 使用Spring框架的好处
转自:https://www.cnblogs.com/hoobey/p/6032506.html 在SSH框假中spring充当了管理容器的角色.我们都知道Hibernate用来做持久层,因为它将JD ...
- SSM-Spring-19:Spring中JdbcTemplate
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- Spring自带一个ORM持久化框架JdbcTemplate,他可以说是jdbc的加强版,但是对最细微的控制肯 ...
- 实现基于Spring框架应用的权限控制系统(转)
为什么80%的码农都做不了架构师?>>> 前注:当我摸到了通过filter拦截权限,通过AOP拦截方法,通过权限控制菜单的时候,猛然发现这一切的一切已经是别人已经发明好的轮子. ...
- spring框架使用Quartz执行定时任务实例详解
版权声明:本文为博主原创文章,如需转载,请标明出处. https://blog.csdn.net/alan_liuyue/article/details/80382324 Quartz简介 1.Qua ...
最新文章
- MOSES | 分子生成模型的基准平台
- 怎样开发一个 Node.js 命令行工具包
- codeforces 939C Convenient For Everybody 简直羞耻
- 物联网避坑 3 大指南!
- Hadoop tutorial - 3 Hello MapReduce- 2015-3-30
- UCHome风格模版 框架核心代码提取
- Hololens2 与Unity 远程连接调试程序和调试部署
- Google sheet 设置下拉列表
- 农民工看完都学会了!Android开发岗还不会这些问题,跳槽薪资翻倍
- C1 驾驶证考试科目二考试心得
- linux下puts和gets命令用法,puts()和gets()函数(示例代码)
- csv是什么意思中文_csv文件是什么意思
- VB不能加载MSCOMCTL.OCX所需文件
- python考研选什么专业好就业_人工智能考研专业就业怎么样 哪些院校开设人工智能专业...
- 有趣的灵魂是什么样的
- 【React Native】深入理解Native与RN通信原理
- Unity中的设备唯一码GAID、IDFA,用于广告跟踪和数据统计
- 2022年API安全研究报告
- Linux网络编程基础3:数据读写
- GMTSAR合成孔径雷达干涉测量InSAR数据处理、形变信息提取与分析等实践技术应用