文章目录
spring第四章-AOP
一、目标
1、jdbcTemplate的使用
2、spring的事务控制
3、了解spring5的新特性
二、jdbcTemplate的使用
1、jdbcTemplate的介绍
jdbc --- dbutils -- jdbcTemplate(spring 提供) -- mybatis(主流) -- spring data jpa(趋势)
2、数据源配置
a. c3p0数据源
<!--c3p0数据源-->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!--引入外部属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--配置c3p0数据源-->
<bean id="c3p0DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
b. dbcp 数据源
<!--dbcp数据源-->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<!--dbcp数据源-->
<bean id="dbcpDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
c. spring jdbc 自带数据源,包含了JdbcTemplate对象
<!--spring自带数据源-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--spring自带的数据源-->
<bean id="springDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
3、jdbcTemplate的CRUD
package com.sgw;
import com.sgw.domain.Account;
import com.sgw.mapper.AccountRowMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
/**
* 查询使用query
* 增删改:update
*
* queryForList :查询返回一个List集合,Map集合
* query(sql ,属性与列的映射对象,参数):返回值:List<pojo>
* queryForObject :针对于返回一个对象
* update(sql ,参数):执行增删改操作
*
* @author
* @Company http://www.sgw.com
* @Version 1.0
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestJdbcTemplate {
@Autowired
JdbcTemplate jdbcTemplate;
@Test
public void testFindAll(){
String sql = "select * from account";
// 方法返回值是List集合,list中是map、集合
// List<Map<String, Object>> accountList = jdbcTemplate.queryForList(sql);
// for (Map<String, Object> map : accountList) {
// System.out.println(map);
// }
List<Account> accountList = jdbcTemplate.query(sql, new AccountRowMapper());
for (Account account : accountList) {
System.out.println(account);
}
}
@Test
public void testFindById(){
String sql = "select * from account where id = ?";
// List<Account> accountList = jdbcTemplate.query(sql, new AccountRowMapper(), 5);
// System.out.println(accountList.size() == 1 ?accountList.get(0):"结果为null");
// queryForObject(SQL语句,列与属性的映射, 参数):掌握
Account account = jdbcTemplate.queryForObject(sql, new AccountRowMapper(), 5);
System.out.println(account);
// queryForObject(sql语句,参数列表(必须是数组类型), jdbcTemplate 自带映射:必须保证属性和列名一致)
// Account account = jdbcTemplate.queryForObject(sql, new Object[]{1}, new BeanPropertyRowMapper<>(Account.class));
// System.out.println(account);
}
@Test
public void testSave(){
String sql = "insert into account values(null , ? ,?)";
jdbcTemplate.update(sql ,"zhangsan", 10000);
}
@Test
public void testUpdate(){
String sql = "update account set money = ?, name = ? where id = ?";
jdbcTemplate.update(sql ,1000,"lisi",4);
}
@Test
public void testDel(){
String sql = "delete from account where id = ?";
jdbcTemplate.update(sql , 4);
}
@Test
public void testGetTotalCount(){
String sql = "select count(*) from account";
// queryForObject(sql语句, 返回值类型)
Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
System.out.println(count);
}
}
4、在dao中使用jdbcTemplate方法一
a. applicationContext.xml
<!--创建jdbcTemplate模板对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="springDataSource"></property>
</bean>
b.在dao层中使用模板对象
@Repository
public class AccountDaoImpl implements AccountDao {
//自动注入模板对象
@Autowired
JdbcTemplate jdbcTemplate;
}
5、在dao中使用jdbcTemplate方法二
a. 在dao实现类中继承接口JdbcDaoSupport类
public class AccountDaoImpl2 extends JdbcDaoSupport implements AccountDao {
b.所有的dao对象需要在xml中创建,需要通过set方法注入数据源对象
<!--创建dao层对象-->
<bean id="accountDao" class="com.sgw.dao.impl.AccountDaoImpl2">
<!--通过set方法注入数据源-->
<property name="dataSource" ref="springDataSource"></property>
</bean>
三、spring的事务控制
1、spring事务控制的api介绍–事务管理类
org.springframework.orm.hibernate5.HibernateTransactionManager: 在hibernate环境下使用
rg.springframework.jdbc.datasource.DataSourceTransactionManager: 在jdbcTemplate,mybatis(ibatis)环境下使用
2、事务的特性
a、事务的四个特性
原子性: 不可再分割
隔离性: 事务之间的隔离级别
一致性: 要么全部完成,要么全部不完成
持久性: 一旦提交持久化到数据中
b、隔离级别
读未提交:read uncommited
产生的问题:脏读,幻读,不可重复读
脏读:读到了未提交的数据
不可重复读:
幻读(虚读):
读已提交:read commited
产生的问题:幻读,不可重复读
解决的问题:脏读
重复读: repeatable read
产生的问题:幻读
解决的问题:脏读,不可重复读
串行化(序列化): serializable
产生的问题:null
解决的问题: 所有的问题
隔离级别最高,效率最低
c、数据库的支持的隔离级别 -- 一般情况下选择都是默认的隔离级别
mysql:支持:read uncommited read commited repeatable read serializable 支持三个隔离级别
默认的隔离级别:repeatable read
Oracle支持:read commited serializable read only(只读)
默认的隔离级别:read commited
3、事务的传播
a. 掌握
REQUIRED: 必要的: 如果没有事务,则新建一个事务,如果有事务,加入这个事务当中, spring指定为默认值
增删改:
SUPPORTS: 支持的: 如果没有事务,非事务执行,如果有事务,加入这个事务当中
查询
b. 了解
MANDATORY: 可以使用当前的事务,如果没有事务,抛出异常
REQUERS_NEW: 新建一个事务,如果存在事务,则挂起事务
NOT_SUPPORTED: 必须非事务执行,如果有事务,则挂起事务
NEVER: 非事务执行,如果存在事务,抛出异常
NESTED: 有事务,嵌套执行,没有事务,执行REQUIRED
4、是否为只读的事务
a.如果是查询,则为只读的事务 readOnly=true
b.如果是增删改,则为非只读的事务,readOnly=false=
5、基于xml声明式事务管理(配置文件)(重点)(推荐)
a. 编程式事务管理:在业务层写了事务技术代码
b. 声明式事务管理:在配置文件声明事务对象,管理事务,业务层中没有任何事务代码
1) 引入依赖:
<!--aop的切面配置需要的jar包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<!--spring 的事务管理jar包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--spring 的基础包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--spring自带数据源, 包含了事务管理类 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--两个测试包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
2) 编写配置文件
<!--创建事务管理器对象-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源属性:事务存在连接中- 连接存在连接池(数据源)中-->
<property name="dataSource" ref="springDataSource"></property>
</bean>
<!--事务的增强: 过滤方法是否需要拦截
id:唯一的标识
transaction-manager:指定事务管理器
-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!--增强:方法的过滤-->
<tx:attributes>
<!--指定需要拦截的方法
isolation:隔离级别, 一般选择默认的
propagation:传播的行为,
read-only: 是否为只读的事务,增删改:非只读事务 read-only=false
查询:只读的事务:read-only=true
find* :通配符配置,只要以 find开头即可
-->
<!--配置方式一:-->
<!--增删改-->
<!--<tx:method name="insert*" />-->
<!--<tx:method name="add*" />-->
<!--<tx:method name="update*" />-->
<!--<tx:method name="del*" />-->
<!--<tx:method name="delete*" />-->
<!--<tx:method name="save*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1"/>-->
<!--查询-->
<!--<tx:method name="find*" propagation="SUPPORTS" read-only="true" ></tx:method>-->
<!--<tx:method name="select*" propagation="SUPPORTS" read-only="true" ></tx:method>-->
<!--<tx:method name="query*" propagation="SUPPORTS" read-only="true"></tx:method>-->
<!--<tx:method name="get*" isolation="DEFAULT" propagation="SUPPORTS" read-only="true" timeout="-1"></tx:method>-->
<!--配置方式二-->
<tx:method name="find*" propagation="SUPPORTS" read-only="true"></tx:method>
<tx:method name="select*" propagation="SUPPORTS" read-only="true"></tx:method>
<tx:method name="query*" propagation="SUPPORTS" read-only="true"></tx:method>
<tx:method name="get*" propagation="SUPPORTS" read-only="true"></tx:method>
<!--其他方法的配置方法-->
<tx:method name="*" propagation="REQUIRED" read-only="false"></tx:method>
</tx:attributes>
</tx:advice>
<!--aop的配置:
切面= 切入点 +通知(增强)
-->
<aop:config>
<!--切面配置
advice-ref: 通知关联对象
pointcut: 切入点:
-->
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.sgw.service.impl.*.*(..))"></aop:advisor>
</aop:config>
3) 业务层
业务层不需要任何事务管理,只需要提供业务代码即可
6、基于注解的配置(重点)
a. 引入依赖
与xml完全一致
b. 配置文件
1)配置事务管理类
<!--创建事务管理器对象-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源属性:事务存在连接中- 连接存在连接池(数据源)中-->
<property name="dataSource" ref="springDataSource"></property>
</bean>
2) 开启事务的注解管理
<!--transaction-manager: 关联事务管理器对象-->
<tx:annotation-driven transaction-manager="txManager"></tx:annotation-driven>
<!--开启aop的注解:自动代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
c. 业务层
在类上标记注解:@Transactional, 类中所有的方法都会使用事务管理
在方法上标记注解:@Transactional:只有该方法按照事务执行
d.属性介绍
@Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, readOnly = false,timeout = -1)