Spring ( 五 )Spring之数据访问与事务管理

个人博客网:https://wushaopei.github.io/    (你想要这里多有)

一、Spring之数据访问

1、Spring数据访问工程环境搭建

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

jdbc.properties配置文件:

jdbc.user=root
jdbc.password=root
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/jdbctemplate

Spring ( 五 )Spring之数据访问与事务管理

applicationContext.xml配置文件:

        <!-- 加载jdbc.properties配置文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}" />
<property name="password" value="${jdbc.password}" />
<property name="driverClass" value="${jdbc.driverClass}" />
<property name="jdbcUrl" value="${jdbc.url}" />
</bean> <!-- jdbcTempalte是一个工具类,专门用来执行sql语句 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>

Spring ( 五 )Spring之数据访问与事务管理

测试代码:

     @Test
public void testDataSource() throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource = (DataSource) applicationContext.getBean("dataSource");
System.out.println( dataSource.getConnection() );
System.out.println(applicationContext.getBean("jdbcTemplate"));
}

Spring ( 五 )Spring之数据访问与事务管理

2、Spring之JdbcTemplate使用

在Spring中提供了对jdbc的封装类叫JdbcTemplate。它可以很方便的帮我们执行sql语句,操作数据库。

先准备单表的数据库数据

drop database  if exists jdbctemplate;

create database jdbctemplate;

use jdbctemplate;

CREATE TABLE `employee` (
`id` int(11) primary key AUTO_INCREMENT,
`name` varchar(100) DEFAULT NULL,
`salary` decimal(11,2) DEFAULT NULL
); insert into `employee`(`id`,`name`,`salary`)
values (1,'李三',5000.23),(2,'李四',4234.77),(3,'王五',9034.51),
(4,'赵六',8054.33),(5,'孔七',6039.11),(6,'曹八',7714.11); select * from employee;

Spring ( 五 )Spring之数据访问与事务管理

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

创建一个与数据库表对应的javaBean类

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

3、将id=5的记录的salary字段更新为1300.00

@ContextConfiguration(locations="classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class JdbcTempalteTest {
@Autowired
JdbcTemplate jdbcTemplate;
@Test
public void test2() throws Exception {
// 实验2:将id=5的记录的salary字段更新为1300.00
String sql = "update employee set salary = ? where id = ?";
System.out.println( jdbcTemplate.update(sql, new BigDecimal(1300),5) );
}
}

Spring ( 五 )Spring之数据访问与事务管理

4、批量插入

        @Test
public void test3() throws Exception {
String sql = "insert into employee(`name`,`salary`) values(?,?)";
// jdbcTemplate.update(sql, "尚硅谷94V587",new BigDecimal(100000)); //插入一条 List<Object[]> batchArgs = new ArrayList<Object[]>();
batchArgs.add(new Object[] {"新来的1",new BigDecimal(30000)});
batchArgs.add(new Object[] {"新来的2",new BigDecimal(40000)});
batchArgs.add(new Object[] {"新来的3",new BigDecimal(50000)}); jdbcTemplate.batchUpdate(sql, batchArgs);
}

Spring ( 五 )Spring之数据访问与事务管理

分析图解:

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

数据库结果:

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

5、查询id=5的数据库记录,封装为一个Java对象返回

        @Test
public void test4() throws Exception {
String sql = "select id,name,salary from employee where id = ?";
// rowMapper是将查询到的ResultSet的每一行记录转换成为一个javaBean对象 Employee employee = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Employee>(Employee.class), 5);
System.out.println( employee );
}

Spring ( 五 )Spring之数据访问与事务管理

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

6、查询salary>4000的数据库记录,封装为List集合返回

public void test5() throws Exception {
// QueryRunner
// update() ====>>>> insert、update、delete
// 到底是查一条,还是查多条记录,由ResultSetHandler决定
// Jdbctempalte
// update() ====>>>> insert、update、delete
// queryForObject 查一个对象
// query 查多个对象 String sql = "select id,name,salary from employee where salary > ?";
List<Employee> employees = jdbcTemplate.query(sql,
new BeanPropertyRowMapper<Employee>(Employee.class), new BigDecimal(4000));
employees.forEach(System.out::println);
}

Spring ( 五 )Spring之数据访问与事务管理

7、查询最大salary

	@Test
public void test6() throws Exception {
String sql = "select max(salary) from employee";
BigDecimal maxSalary = jdbcTemplate.queryForObject(sql, BigDecimal.class);
System.out.println( maxSalary );
}

Spring ( 五 )Spring之数据访问与事务管理

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

配置NamedParameterJdbcTemplate

        <!-- 配置可以解析执行具名参数的sql的JdbcTemplate -->
<bean id="namedParameterJdbcTemplate"
class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg index="0" ref="dataSource" />
</bean>

Spring ( 五 )Spring之数据访问与事务管理

Test中添加以下注解,用于注入xml中解析执行具名参数所用

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

        @Test
public void test7() throws Exception {
/**
* :name 就是占位符,参数。名是name。 一起,就是具名参数
*/
String sql = "insert into employee(`name`,`salary`) values(:name,:salary)"; Map<String, Object>paramMap = new HashMap<>();
paramMap.put("name", "这是具名参数的name");
paramMap.put("salary", new BigDecimal(100000)); namedParameterJdbcTemplate.update(sql, paramMap);
}

Spring ( 五 )Spring之数据访问与事务管理

Mysql 结果:

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

9、重复8,以SqlParameterSource形式传入参数值

        @Test
public void test8() throws Exception {
/**
* :name 就是占位符,参数。名是name。 一起,就是具名参数
*/
String sql = "insert into employee(`name`,`salary`) values(:name,:salary)";
Employee employee = new Employee(null, "新插入的帅哥", new BigDecimal(3000));
namedParameterJdbcTemplate.update(sql, new BeanPropertySqlParameterSource(employee));
}

Spring ( 五 )Spring之数据访问与事务管理

10、创建Dao,自动装配JdbcTemplate对象

@Repository
public class EmployeeDao { @Autowired
private JdbcTemplate jdbcTemplate; public Employee queryEmployeeById(Integer id) {
String sql = "select id,name,salary from employee where id = ?";
Employee employee = jdbcTemplate.queryForObject(sql,
new BeanPropertyRowMapper<Employee>(Employee.class), id);
return employee;
} }

Spring ( 五 )Spring之数据访问与事务管理

配置内容:

	<context:component-scan base-package="com.webcode"></context:component-scan>

Spring ( 五 )Spring之数据访问与事务管理

测试代码:

@ContextConfiguration(locations = "classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class JdbcTempalteTest { @Autowired
JdbcTemplate jdbcTemplate; @Autowired
NamedParameterJdbcTemplate namedParameterJdbcTemplate; @Autowired
EmployeeDao employeeDao; @Test
public void test9() throws Exception {
System.out.println( employeeDao.queryEmployeeById(1) );
}
}

Spring ( 五 )Spring之数据访问与事务管理

11、通过继承JdbcDaoSupport创建JdbcTemplate的Dao

@Repository
public class EmployeeDao extends JdbcDaoSupport { // @Autowired
// private JdbcTemplate jdbcTemplate; public Employee queryEmployeeById(Integer id) {
String sql = "select id,name,salary from employee where id = ?";
Employee employee = getJdbcTemplate().queryForObject(sql,
new BeanPropertyRowMapper<Employee>(Employee.class), id);
return employee;
} @Autowired
public void setJdbcTemplate2(JdbcTemplate jdbcTemplate) {
setJdbcTemplate(jdbcTemplate);
} }

Spring ( 五 )Spring之数据访问与事务管理

源码分析方法实现与调用过程:

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

二、声明式事务

事务分为声明式和编程式两种:

声明式事务:声明式事务是指通过注解(和xml配置)的形式对事务的各种特性进行控制和管理。

编码式(编程式)事务:指的是通过编码的方式实现事务的声明。

1、编码方式实现事务:

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

2、声明式事务环境搭建

2.1、准备测试数据库

##创建tx数据库
drop database if exists `tx`;
CREATE database `tx`;
##切换tx数据库
USE `tx`; ##删除用户表
DROP TABLE IF EXISTS `user`;
##创建用户表
CREATE TABLE `user` (
`id` int primary key auto_increment,
`username` varchar(50) NOT NULL,
`money` int(11) DEFAULT NULL
);
##插入数据
insert into `user`(`username`,`money`) values ('张三',1000),('李四',1000); ##删除图书表
drop table if exists `book`;
##创建图书表
create table `book`(
`id` int primary key auto_increment,
`name` varchar(500) not null,
`stock` int
);
##插入数据
insert into book(`name`,`stock`) values('java编程思想',100),('C++编程思想',100); ##查看数据
select * from book;
select * from user;

Spring ( 五 )Spring之数据访问与事务管理

   2.2、创建一个Java工程,导入Jar包

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

@Repository
public class UserDao { @Autowired
JdbcTemplate jdbcTemplate; public void updateUser() {
jdbcTemplate.update("update user set username = '用户表被修改了'");
}
} @Repository
public class BookDao { @Autowired
JdbcTemplate jdbcTemplate; public void updateBook() {
jdbcTemplate.update("update book set name = '图书表被修改了'");
}
}

Spring ( 五 )Spring之数据访问与事务管理

Service

@Service
public class TransactionService { @Autowired
private UserDao userDao; @Autowired
private BookDao bookDao; public void multiUpdate() {
userDao.updateUser();
int i = 12 / 0 ;
bookDao.updateBook();
} }

Spring ( 五 )Spring之数据访问与事务管理

3、测试Service的默认事务

【1】测试service服务层的默认事务

默认一个sql一个事务

@ContextConfiguration(locations="classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringTest { @Autowired
TransactionService transactionService; @Test
public void testMultiUpdate() throws Exception {
transactionService.multiUpdate();
} }

Spring ( 五 )Spring之数据访问与事务管理

异常的演示

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

Spring事务引入的分析------PlatformTransactionManager类简单介绍

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

4、使用Spring的注解声明事务管制

【1】测试Spring的声明式事务

TransactionService中的修改

        /**
* @Transactional表示当前方法有事务管理
*/
@Transactional
public void multiUpdate() {
userDao.updateUser();
// int i = 12 / 0 ;
bookDao.updateBook();
}

Spring ( 五 )Spring之数据访问与事务管理

配置文件中的内容:

        <!--
配置事务管理===等价于切面
-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- dataSource一定要是操作数据库的数据源 -->
<property name="dataSource" ref="dataSource" />
</bean> <!--
开启事务的注解支持==做aop
transaction-manager="transactionManager" 使用哪个事务管理器来管理事务
如果事务管理器的id就叫transactionManager,
则:属性transaction-manager可以省略
-->
<tx:annotation-driven transaction-manager="transactionManager"/>

Spring ( 五 )Spring之数据访问与事务管理

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

5、noRollbackFor和noRollbackForClassName测试不回滚的异常

【1】noRollbackFor和noRollbackForClassName测试不回滚的异常

        /**
* @throws FileNotFoundException
* @Transactional表示当前方法有事务管理<br/>
* Spring底层默认是回滚运行时异常,以运行时子异常<br/>
* noRollbackFor设置哪些异常不回滚事务<br/>
* noRollbackForClassName设置哪些类型的异常不回滚事务<br/>
*/
@Transactional(noRollbackForClassName="java.lang.ArithmeticException")
public void multiUpdate() throws FileNotFoundException {
userDao.updateUser();
int i = 12 / 0 ;
bookDao.updateBook();
}

Spring ( 五 )Spring之数据访问与事务管理

运行时异常回滚

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

编译异常:不回滚

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

6、自定义设置回滚异常

【1】rollbackFor和rollbackForClassName回滚的异常

        /**
* @throws FileNotFoundException
* @Transactional表示当前方法有事务管理<br/>
* Spring底层默认是回滚运行时异常,以运行时子异常<br/>
* rollbackFor是设置哪个异常回滚事务<br/>
* rollbackForClassName是设置哪个异常类名也会回滚事务<br/>
*/
@Transactional()
public void multiUpdate() throws FileNotFoundException {
userDao.updateUser();
// int i = 12 / 0 ;
int i = 12 ;
if (i == 12) {
throw new FileNotFoundException("asdf");
}
bookDao.updateBook();
}

Spring ( 五 )Spring之数据访问与事务管理

7、事务的只读属性

实验4:测试readOnly只读属性

        /**
* @throws FileNotFoundException
* @Transactional表示当前方法有事务管理<br/>
* Spring底层默认是回滚运行时异常,以运行时子异常<br/>
* readOnly 设置当前执行的sql语句是不是只是select查询
* 如果设置为false就允许执行insert,delete、update
*/
@Transactional(readOnly=true)
public void multiUpdate() throws FileNotFoundException {
userDao.updateUser();
bookDao.updateBook();
}

Spring ( 五 )Spring之数据访问与事务管理

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

8、事务超时属性timeout(秒为单位)

        /**
* @throws FileNotFoundException
* @throws InterruptedException
* @Transactional表示当前方法有事务管理<br/>
* Spring底层默认是回滚运行时异常,以运行时子异常<br/>
* timeout设置连接的超时属性。
* timeout=3表示3秒后不允许再执行sql语句
*/
@Transactional(timeout=3)
public void multiUpdate() throws InterruptedException {
userDao.updateUser();
Thread.sleep(4000);
bookDao.updateBook();
}

Spring ( 五 )Spring之数据访问与事务管理

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

10、事务的传播特性propagation

什么是事务的传播行为:

当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。

事务的传播行为可以由传播属性指定。Spring定义了7种类传播行为。

事务的传播特性,有以下几种类型:

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

11、注解演示事物传播特性

UserService

BookService

TransactionService

实验1:大小事务传播特性都是REQUIRED

        @Transactional(propagation = Propagation.REQUIRED)
public void multiTransaction() {
@Transactional(propagation = Propagation.REQUIRED)
public void updateBook() {
@Transactional(propagation=Propagation.REQUIRED)
public void updateUser() {

Spring ( 五 )Spring之数据访问与事务管理

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

实验2:大小事务传播特性都是REQUIRES_NEW

        @Transactional(propagation = Propagation.REQUIRES_NEW)
public void multiTransaction()
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateBook()
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateUser()

Spring ( 五 )Spring之数据访问与事务管理

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

实验3:大事务是REQUIRED,小事务都是REQUIRES_NEW

        @Transactional(propagation = Propagation.REQUIRED)
public void multiTransaction()
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateBook()
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateUser()

Spring ( 五 )Spring之数据访问与事务管理

实验3跟实验2一样。

实验4:大事务是REQUIRED,小1REQUIRED,小2REQUIRES_NEW

	@Transactional(propagation = Propagation.REQUIRED)
public void multiTransaction()
@Transactional(propagation = Propagation.REQUIRED)
public void updateBook()
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateUser()

Spring ( 五 )Spring之数据访问与事务管理

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

三、xml配置式事务声明

去掉。所有@Transactional的注解。

配置文件内容:

<?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 http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <context:component-scan base-package="com.webcode"></context:component-scan> <!-- 加载jdbc.properties配置文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}" />
<property name="password" value="${jdbc.password}" />
<property name="driverClass" value="${jdbc.driverClass}" />
<property name="jdbcUrl" value="${jdbc.url}" />
</bean> <!-- jdbcTempalte是一个工具类,专门用来执行sql语句 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean> <!-- 配置事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean> <!-- 配置事务特性 -->
<tx:advice id="tx_advice" transaction-manager="transactionManager">
<tx:attributes>
<!--
配置一个或多个方法的特性
<tx:method name="save*" propagation="REQUIRED"/>
name表示方法名
save*表示方法名以save打头的方法都算
propagation="REQUIRED"表示必须要有事务
-->
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<!--
精确匹配方法名
精确匹配优先 ===>>> 半模糊(update*) ====>>>> *
-->
<tx:method name="multiTransaction" propagation="REQUIRED"/>
<tx:method name="updateUser" propagation="REQUIRES_NEW"/>
<!--
*表示剩下的方法
read-only="true"会做一些优化
-->
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice> <!--
配置代理
-->
<aop:config>
<!-- advisor是配置切面 -->
<aop:advisor advice-ref="tx_advice"
pointcut="execution(public * com.webcode.service..*Service*.*(..))"/>
</aop:config> </beans>

Spring ( 五 )Spring之数据访问与事务管理

Spring ( 五 )Spring之数据访问与事务管理Spring ( 五 )Spring之数据访问与事务管理

四、Spring整合Web

1、在web工程中添加Spring的jar包

Spring的核心包
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
aop包
spring-aop-4.0.0.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
JDBC-ORM包
spring-jdbc-4.0.0.RELEASE.jar
spring-orm-4.0.0.RELEASE.jar
spring-tx-4.0.0.RELEASE.jar
Spring的web整合包
spring-web-4.0.0.RELEASE.jar
测试包
spring-test-4.0.0.RELEASE.jar

Spring ( 五 )Spring之数据访问与事务管理

  • ServletContext在web工程启动的时候创建
  • 在Web工程停止的时候销毁

整合Spring和Web容器分两个步骤:

1、导入spring-web-4.0.0.RELEASE.jar

2、在web.xml配置文件中配置org.springframework.web.context.ContextLoaderListener监听器监听ServletContext的初始化

3、在web.xml配置文件中配置contextConfigLocation上下文参数。配置Spring配置文件的位置,以用于初始化Spring容器

web.xml中配置

 <context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

Spring ( 五 )Spring之数据访问与事务管理

获取WebApplicationContext上下文对象的方法如下:

方法一(推荐):

WebApplicationContextUtils.getWebApplicationContext(getServletContext())

方法二(不推荐):

getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

上一篇:MapReduce原理


下一篇:FolderBrowserDialog