1.Spring提供的一个操作数据库的技术JdbcTemplate,是对Jdbc的封装。语法风格非常接近DBUtils。
  JdbcTemplate可以直接操作数据库,加快效率,而且学这个JdbcTemplate也是为声明式事务做准备,毕竟要对数据库中的数据进行操纵!
  JdbcTemplate中并没有提供一级缓存,以及类与类之间的关联关系!就像是spring提供的一个DBUtils。
  Spring对数据库的操作使用JdbcTemplate来封装JDBC,结合Spring的注入特性可以很方便的实现对数据库的访问操作。使用JdbcTemplate可以像JDBC一样来编写数据库的操作代码
 
2.为啥要使用Jdbc_template进行开发呢?
    Spring对数据库的操作在jdbc上面做了深层次的封装,使用spring的注入功能,可以把DataSource注册到JdbcTemplate之中。
    Spring提供的JdbcTemplate对jdbc做了封装,大大简化了数据库的操作。找到Spring JdbcTemplate源码,可以看到如下方法:
        Connection con = DataSourceUtils.getConnection(getDataSource());
    如果直接使用JDBC的话,需要我们加载数据库驱动、创建连接、释放连接、异常处理等一系列的动作;繁琐且代码看起来不直观。
    此外,Spring提供的JdbcTempate能直接数据对象映射成实体类,不再需要获取ResultSet去获取值/赋值等操作,提高开发效率;
 
3.配置环境
①导入jar包
  [1]IOC容器需要的jar包   
            commons-logging-1.1.3.jar
            spring-aop-4.0.0.RELEASE.jar  //注解会使用到的包
            spring-beans-4.0.0.RELEASE.jar
            spring-context-4.0.0.RELEASE.jar
            spring-core-4.0.0.RELEASE.jar
            spring-expression-4.0.0.RELEASE.jar
 
  [2]MySQL驱动、C3P0jar包
            c3p0-0.9.1.2.jar
            mysql-connector-java-5.1.37-bin.jar
 
  [3]JdbcTemplate需要的jar包   
            spring-jdbc-4.0.0.RELEASE.jar
            spring-orm-4.0.0.RELEASE.jar
            spring-tx-4.0.0.RELEASE.jar
 
②在IOC容器中配置数据源
 
<!-- 加载properties文件中 信息 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置数据源 -->
<bean id="comboPooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
</bean>

其中,新建 jdbc.properties 文件

内容:

jdbc.username=root
jdbc.password=123456
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/jdbc_template

③在IOC容器中配置JdbcTemplate对象的bean,并将数据源对象装配到JdbcTemplate对象中

<!-- 配置JdbcTemplate对应的bean, 并装配dataSource数据源属性-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="comboPooledDataSource"></property>
</bean>

实验1:测试数据源
 
@Test
public void test() throws SQLException{
ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource bean = ioc.getBean(DataSource.class);
System.out.println(bean.getConnection());
}

实验2:将emp_id=5的记录的salary字段更新为1300.00【更新操作】

不用我们自己再去获取数据库连接信息了,而是直接传递sql语句及其参数!
public class TestJDBCTemplate {

      private ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
private JdbcTemplate bean = ioc.getBean(JdbcTemplate.class); @Test
public void test() throws SQLException{
String sql = "UPDATE employee SET salary = ? WHERE emp_id = ?";
bean.update(sql, 1300,5);//第一个是sql语句,后面的按着顺序传入参数即可,这个update方法是接收的可变参数!
}
}
 实验3:批量插入  bean.batchUpdate(sql, list);
 
public class TestJDBCTemplate {

      private ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
private JdbcTemplate bean = ioc.getBean(JdbcTemplate.class); @Test
public void test() throws SQLException{
String sql="INSERT INTO employee(emp_name,salary) VALUES(?,?)"; List<Object[]> list = new ArrayList<Object[]>();
list.add(new Object[]{"Tom2015",1000});
list.add(new Object[]{"Tom2016",2000});
list.add(new Object[]{"Tom2017",3000}); bean.batchUpdate(sql, list);
}
}
 实验4:查询emp_id=5的数据库记录,封装为一个Java对象返回
 
 分析:封装为一个对象返回的话,首先我们需要有一个与数据表对应的实体类!

public class TestJDBCTemplate {

      private ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
private JdbcTemplate bean = ioc.getBean(JdbcTemplate.class); @Test
public void test(){
//需要注意的是:sql语句中的别名要与对应实体类的属性名保持一致!
String sql = "SELECT emp_id AS empId,emp_name AS empName,salary FROM employee WHERE emp_id=?"; //RowMapper是一个接口,这里我们使用其子类
RowMapper<Employee> rowMapper = new BeanPropertyRowMapper<Employee>(Employee.class);
//最后一个参数是可变参数,用于向sql语句中依次传递参数!
Employee employee = bean.queryForObject(sql, rowMapper, 5);
System.out.println(employee);
}
}

实验5:查询salary>4000的数据库记录,封装为List集合返回

 
可以看出,查询结果是一个实体还是一个list列表是靠bean对象的不同方法实现的!
public class TestJDBCTemplate {

      private ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
private JdbcTemplate bean = ioc.getBean(JdbcTemplate.class); @Test
public void test(){
//需要注意的是:sql语句中的别名要与对应实体类的属性名保持一致!
String sql = "SELECT emp_id AS empId,emp_name AS empName,salary FROM employee WHERE salary > ?"; //RowMapper是一个接口,这里我们使用其子类
RowMapper<Employee> rowMapper = new BeanPropertyRowMapper<Employee>(Employee.class);
//该query方法查询出来的是一个list列表,query方法的最后一个参数是可变参数!
List<Employee> list = bean.query(sql, rowMapper, 4000); for (Employee employee : list) {
System.out.println(employee);
}
}
}

实验6:查询最大salary

 
public class TestJDBCTemplate {

    private ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
private JdbcTemplate bean = ioc.getBean(JdbcTemplate.class); @Test
public void test01(){
String sql = "SELECT MAX(salary) FROM employee";
//需要指定返回值的类型,而且类型必须是包装类型
Double maxSalary = bean.queryForObject(sql, Double.class);
System.out.println(maxSalary);
}
}

实验7:使用带有具名参数的SQL语句插入一条员工记录,并以Map形式传入参数值

 
具名参数:是指基于名称的,前面我们使用的都是用 ? 作为占位符,是基于位置的!
如果要使用具名参数的sql语句就必须在spring配置文件中配置NamedParameterJdbcTemplat这个模板类
原来的JdbcTemplate,因为JdbcTemplate不能完成这样的任务!
              
 在 applicationContext.xml 文件中继续配置     
<!-- 为了执行带有具名参数的SQL语句,需要配置NamedParameterJdbcTemplate -->
<!-- 该NamedParameterJdbcTemplate类没有无参构造器,需要传入JdbcTemplate对象或者数据源对象[DataSource] -->
<bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<!-- 不能使用property标签配置 -->
<constructor-arg ref="jdbcTemplate"></constructor-arg>
</bean>

public class TestJDBCTemplate {

      private ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");

      @Test
public void test01(){
NamedParameterJdbcTemplate bean2 = ioc.getBean(NamedParameterJdbcTemplate.class);
String sql="INSERT INTO employee(emp_name,salary) VALUES(:paramName,:paramSalary)";//具名参数与map 的key 值相同
Map<String,Object> paramMap = new HashMap<String,Object>();
paramMap.put("paramName","张学友" );
paramMap.put("paramSalary",1000); bean2.update(sql, paramMap);
}
}

实验8:重复实验7,以SqlParameterSource形式传入参数值

 
public class TestJDBCTemplate {

      private ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");

      @Test
public void test01(){
NamedParameterJdbcTemplate bean2 = ioc.getBean(NamedParameterJdbcTemplate.class);
String sql="INSERT INTO employee(emp_name,salary) VALUES(:empName,:salary)";
//该BeanPropertySqlParameterSource类构造器需要一个对象参数,该对象参数是一个封装了sql语句参数的对象!
//此时要求对象的属性名要和sql中的参数名保持一致!这里我们使用Employee对象来完成
Employee employee= new Employee("郭富城", 1500);
//以实体对象的形式封装具名参数和值
SqlParameterSource source = new BeanPropertySqlParameterSource(employee); bean2.update(sql, source);
}
}
 实验9:创建JdbcTemplateDao,自动装配JdbcTemplate对象
 
 1.创建dao类:

@Repository
public class JdbcTemplateDao {
@Autowired
private JdbcTemplate jdbcTemplate; public void update(){
String sql = "DELETE FROM employee where emp_id = ?";
jdbcTemplate.update(sql, 15);
}
}
 2.测试该dao

public class TestJDBCTemplate {

      private ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
private JdbcTemplate bean = ioc.getBean(JdbcTemplate.class); private JdbcTemplateDao dao = ioc.getBean(JdbcTemplateDao.class);
@Test
public void testEmployeeDao(){
dao.update();
}
}
 

 声明式事务:
 
1.导jar包:
- com.springsource.net.sf.cglib-2.2.0.jar
- com.springsource.org.aopalliance-1.0.0.jar
- com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
- commons-logging-1.1.3.jar
- spring-aop-4.0.0.RELEASE.jar
- spring-aspects-4.0.0.RELEASE.jar
- spring-beans-4.0.0.RELEASE.jar
- spring-context-4.0.0.RELEASE.jar
- spring-core-4.0.0.RELEASE.jar
- spring-expression-4.0.0.RELEASE.jar
- spring-jdbc-4.0.0.RELEASE.jar
- spring-orm-4.0.0.RELEASE.jar
- spring-tx-4.0.0.RELEASE.jar
- c3p0-0.9.1.2.jar
- mysql-connector-java-5.1.37-bin.jar
 
 
2.创建一份jdbc.properties文件 :
jdbc.user=root
jdbc.passowrd=123456
jdbc.url=jdbc:mysql://localhost:3306/tx
jdbc.driver=com.mysql.jdbc.Driver
 
 
3.配置文件,在 JdbcTemplate的配置信息的基础上

<context:component-scan base-package="com.neuedu"></context:component-scan>
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="comboPooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
</bean>
<!-- 以上时JdbcTemplate配置所需 --> <!-- 配置事务管理器 -->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="comboPooledDataSource"></property>
</bean> <!-- 开启基于注解的声明式事务 -->
<!-- 有时候不需要transaction-manager 因为默认值为transactionManager -->
<!-- 如果事务管理器的id为transactionManager就不用写 -->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
 4.在需要进行事务控制的方法上加注解:@Transactional
 
 
5.测试数据源

public class TestDataSource {

       private ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");

       @Test
public void test() throws Exception {
DataSource bean = ioc.getBean(DataSource.class);
System.out.println(bean.getConnection());
}
}
 6.创建 Dao 类
 
  Dao 层的四个方法

@Repository
public class BookDao { @Autowired
private JdbcTemplate template; public double findPriceByIsbn(String isbn){
String sql = "SELECT price FROM book WHERE isbn = ?";
Double price = template.queryForObject(sql, Double.class, isbn);
return price;
} public void updateBookStock(String isbn){
String sql="UPDATE book_stock SET stock = stock -1 WHERE isbn = ?";
template.update(sql, isbn);
} public void updateAccount(String username,Double price){
String sql = "UPDATE account SET balance = balance - ? WHERE username = ?";
template.update(sql, price,username);
} //演示事务的传播机制
public void updateBookPrice(double price,String isbn){
String sql ="UPDATE book SET price = ? WHERE isbn = ?";
template.update(sql, price,isbn);
}
}

7.创建 Service 层

@Service
public class BookService { @Autowired
private BookDao bookDao; @Transactional
public void doCash(String isbn,String username){
double price = bookDao.findPriceByIsbn(isbn);
bookDao.updateBookStock(isbn);
try {
Thread.sleep(1000*5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
bookDao.updateAccount(username, price);
} @Transactional
public void updateBookPrice(double price,String isbn){
bookDao.updateBookPrice(price, isbn);
}
}
 8.测试 Service 中的 doCash 方法:
 
public class TestBookService {

	private ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
@Test
public void test() {
BookService bean = ioc.getBean(BookService.class);
bean.doCash("ISBN-001", "Tom");
}
}
 

 事务的设置
  - 事务的传播行为
  - 事务的隔离级别
  - 事务根据什么异常不进行回滚
  - 事务的超时属性
  - 事务的只读属性
 
事务的传播行为:   -----propagation
 
- REQUIRED :【默认】
如果外层有事务,就会调用外层的事务
如果外层没事务,就自己启动个事务,在自己的事务中运行
当第二个发生异常,第一个也跟着回滚
 

@Transactional(propagation=Propagation.REQUIRED)
public void doCash(String isbn,String username){
double price = bookDao.findPriceByIsbn(isbn);
bookDao.updateBookStock(isbn);
bookDao.updateAccount(username, price);
} @Transactional(propagation=Propagation.REQUIRED)
public void updateBookPrice(double price,String isbn){
bookDao.updateBookPrice(price, isbn);
}
- REQUIRES_NEW:
一定会运行自己的事务
如果外层有事务,那就挂起外层事务
等到自己的事务运行完毕,在继续外层事务
当第二个发生异常,也不会回滚
 

@Transactional(propagation=Propagation.REQUIRES_NEW)
public void doCash(String isbn,String username){
double price = bookDao.findPriceByIsbn(isbn);
bookDao.updateBookStock(isbn);
bookDao.updateAccount(username, price);
} @Transactional(propagation=Propagation.REQUIRES_NEW)
public void updateBookPrice(double price,String isbn){
bookDao.updateBookPrice(price, isbn);
}
- SUPPORTS :
如果外层有事务,那么就在外层事务中运行
如果没有,自己也不启动新事务
 
 
总结:

事务的隔离级别:  ----- isolation
 
比如,当前数据库中的price 为100,输出100;
然后将 price 改为 200,再输出还会是100,默认是REPEATABLE_READ,保持事务数据一致性
改为:READ_COMMITTED,就会随着数据库中的数据的更改,输出也更改
 
@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.READ_COMMITTED)
public void doCash(String isbn,String username){
double price = bookDao.findPriceByIsbn(isbn);
System.out.println(price);
bookDao.updateBookStock(isbn);
bookDao.updateAccount(username, price);
}
不回滚: ------- noRollbackFor={ ArithmeticExpection.class }
默认出现异常回滚,设置之后出现异常不回滚
花✿括号内写异常名称

@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.READ_COMMITTED
,noRollbackFor={ArithmeticException.class}
)
public void doCash(String isbn,String username){
double price = bookDao.findPriceByIsbn(isbn);
bookDao.updateBookStock(isbn);
int i = 10/0;//异常
bookDao.updateAccount(username, price);
}
事务的超时属性:  ------ tiomeout
事务超时=事务开始时到最后一个Statment创建时时间 + 最后一个Statment 的执行时超市时间
 
事务超时时间设置为3秒,sql执行时间为1秒时,事务的不超时的
事务超时时间设置为3秒,sql执行时间为5秒时,这样事务超时!
@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.READ_COMMITTED
,noRollbackFor={ArithmeticException.class}
,timeout=3)
public void doCash(String isbn,String username){
double price = bookDao.findPriceByIsbn(isbn);
bookDao.updateBookStock(isbn);
try {
Thread.sleep(1000*5);
} catch (InterruptedException e) {
e.printStackTrace();
}
bookDao.updateAccount(username, price);
}
事务的只读属性: -----readOnly
 
查询性能更高
 
 

Spring(四)-- JdbcTemplate、声明式事务的更多相关文章

  1. Spring(四)-声明式事务

    Spring-04 声明式事务 1.事务的定义 事务就是由一组逻辑上紧密关联的多个工作单元(数据库操作)而合并成一个整体,这些操作要么都执行,要么都不执行. 2.事务的特性:ACID 1)原子性A : ...

  2. Spring(四)Spring JdbcTemplate&声明式事务

    JdbcTemplate基本使用 01-JdbcTemplate基本使用-概述(了解) JdbcTemplate是spring框架中提供的一个对象,是对原始繁琐的Jdbc API对象的简单封装.spr ...

  3. 170831-关于JdbcTemplate声明式事务-操作步骤-例子

    创建一个动态web工程 加入jar包 3.创建一份jdbc.properties文件 4.在spring配置文件中配置数据源 5.测试数据源: 6.配置jdbcTemplate: 7.创建Dao类 & ...

  4. Spring的 JDBCTemplate和声明式事务控制

    Spring 中的 JdbcTemplate[会用] JdbcTemplate 概述 它是 spring 框架中提供的一个对象,是对原始 Jdbc API 对象的简单封装.spring 框架为我们提供 ...

  5. 11、Spring教程之声明式事务

    1.回顾事务 事务在项目开发过程非常重要,涉及到数据的一致性的问题,不容马虎! 事务管理是企业级应用程序开发中必备技术,用来确保数据的完整性和一致性. 事务就是把一系列的动作当成一个独立的工作单元,这 ...

  6. Spring AOP实现声明式事务代码分析

    众所周知,Spring的声明式事务是利用AOP手段实现的,所谓"深入一点,你会更快乐",本文试图给出相关代码分析. AOP联盟为增强定义了org.aopalliance.aop.A ...

  7. SSM实战——秒杀系统之Service层接口设计与实现、Spring托管、声明式事务

    一:Service层接口设计 准备工作:新建三个包:service包.exception包.dto包,分别用来存放业务接口.自定义异常类.dto类. 1:定义接口 package org.myseck ...

  8. Spring—SSJ集成&声明式事务管理

    1.   课程介绍 1.  SSJ集成;(掌握) 2.  声明式事务管理;(掌握) 什么是三大框架 2.1.  ssh Struts/Struts2 Spring Hibernate 2.2.  ss ...

  9. spring+mybatis之声明式事务管理初识(小实例)

    前几篇的文章都只是初步学习spring和mybatis框架,所写的实例也都非常简单,所进行的数据访问控制也都很简单,没有加入事务管理.这篇文章将初步接触事务管理. 1.事务管理 理解事务管理之前,先通 ...

  10. Spring笔记(5) - 声明式事务@EnableTransactionManagement注解源码分析

    一.背景 前面详解了实现Spring事务的两种方式的不同实现:编程式事务和声明式事务,对于配置都使用到了xml配置,今天介绍Spring事务的注解开发,例如下面例子: 配置类:注册数据源.JDBC模板 ...

随机推荐

  1. Android - 读取XML文件中的数据

    读取XML中存储的数据.将xmlfile.xml存放在assets文件夹中.在activity_main.xml中创建一个textview,用来显示读取到的数据. XML文件内容如下:xmlfile. ...

  2. Jmeter之处理session、cookie以及如何做关联

    具体描述问题之前,我们先了解下session.cookie session.cookie的概念 1.session是放在服务器上的,过期与否取决于服务期的设定,cookie是存在客户端的,过去与否可以 ...

  3. (转)WebSphere MQ基础命令

    --查看MQ版本-- dspmqver --查看队列状态--dspmq --创建队列管理器--crtmqm -q ECIS_QM --删除队列管理器--dltmqm ECIS_QM --启动队列管理器 ...

  4. JavaSE的基础语法之标识符:

    标识符(掌握) (1)就是给类,接口,方法,变量等起名字的字符序列 (2)组成规则: A:英文大小写字母 B:数字 C:$和_ (3)注意事项: A:不能以数字开头 B:不能是java中的关键字 C: ...

  5. 一个最最简易的RPC框架雏形---转载自梁飞的博客

    查阅RPC与HTTP区别的时候, 无意间发现一篇博客,内容是一个简易的RPC服务框架, 仔细一看, 不得了,博主竟然就是阿里dubbo的作者. 原文链接在此: http://javatar.iteye ...

  6. ORACLE - 管理表空间和数据文件

    ORACLE表空间是一个逻辑分区,一个数据文件只能属于一个表空间,一个表空间可以拥有多个数据文件. 一般情况下,如果一个实例分配给多个应用使用,需要创建不同的表空间,每个用户使用自己的表空间. 一.表 ...

  7. C# 接口基础学习

    什么是接口  接口,在表面上是由几个没有主体代码的方法.属性.索引器.事件,或者它们的组合的集合体,有唯一的名称,可以被类或结构或者其他接口所实现(或者也可以说继承).它在形式上可能是如下的样子: i ...

  8. Linux 下实时查看日志

    Linux 下实时查看日志 cat /var/log/*.log 如果日志在更新,如何实时查看 tail -f /var/log/messages 还可以使用 watch -d -n 1 cat /v ...

  9. IoC是什么

    IoC是什么 Ioc-Inversion of Control,即"控制反转",不是什么技术,而是一种设计思想.在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传 ...

  10. 36. leetcode 415. Add Strings

    415. Add Strings Given two non-negative integers num1 and num2 represented as string, return the sum ...