一.基于xml的AOP开发:
(1)xml配置详解:
切点表达式:
表达式语法:
execution([修饰符] 返回值类型 包名.类名.方法名(参数列表))
访问修饰符可以省略
返回值类型、包名、类名、方法名可以使用星号 * 代替,代表任意
包名与类名之间一个点 . 代表当前包下的类,两个点 .. 表示当前包及其子包下的类
参数列表可以使用两个点 .. 表示任意个数,任意类型的参数列表
* 版本一:控制目标对象中,返回值类型void且public修饰的所有方法
execution(public void cn.itcast.service.impl.AccountServiceImpl.*(..))
* 版本二:控制目标对象中,任意修饰符任意返回值的所有方法
execution(* cn.itcast.service.impl.AccountServiceImpl.*(..))
* 版本三:控制service层所有对象的方法
execution(* cn.itcast.service..*.*(..))
切点表达式抽取:
(2)通知类型:
通知的配置语法:
<aop:通知类型 method="通知类中方法名" pointcut="切点表达式"></aop:通知类型>
四大通知:
名称 | 标签 | 说明 |
---|---|---|
前置通知 | aop:before | 在切入点方法之前执行 |
后置通知 | aop:afterReturning | 在切入点方法正常运行之后执行 |
异常通知 | aop:afterThrowing | 在切点方法发生异常的时候执行 |
最终通知 | aop:after | 无论切入点方法执行时是否有异常,都会执行 |
@Component
public class MyAdvice {
// 前置增强
public void before() {
System.out.println("前置通知...");
}
// 后置增强
public void afterReturning(){
System.out.println("后置通知...");
}
// 异常增强
public void afterThrowing(){
System.out.println("异常通知...");
}
// 最终增强
public void after(){
System.out.println("最终通知...");
}
}
注意: 一般情况下,我们不会同时使用四大通知, 因为xml配置顺序可能会打乱我们的执行计划。
重要: 四大通知一般单独使用:
环绕通知:
名称 | 标签 | 说明 |
---|---|---|
环绕通知 | aop:around | 可以灵活实现四大通知的所有效果 |
环绕通知的代码编写,更贴近于动态代理的底层代码
注意:测试环绕通知,需要注释掉四大通知:
// 环绕通知
// Proceeding(运行)JoinPoint(连接点) = 切点
public void around(ProceedingJoinPoint pjp){
try {
System.out.println("前置通知...");
// 执行切点(调用目标对象原有的方法...)
pjp.proceed();
System.out.println("后置通知...");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("异常通知...");
} finally {
System.out.println("最终通知...");
}
}
<aop:around method="around" pointcut-ref="myPointcut"></aop:around>
总结:
* aop织入的配置
<aop:config>
<aop:aspect ref=“通知类”>
<aop:before method=“通知方法名称” pointcut=“切点表达式"></aop:before>
</aop:aspect>
</aop:config>
* 通知的类型
前置通知、后置通知、异常通知、最终通知
环绕通知
* 切点表达式
execution([修饰符] 返回值类型 包名.类名.方法名(参数列表))
(2)基于xml的AOP开发
MyAdvice:
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAdvice {
public void before(){
System.out.println("前置通知before");
}
public void afterRutruning(){
System.out.println("后置通知afterRutruning");
}
public void afterThrowing(){
System.out.println("异常通知afterThrowing");
}
public void after(){
System.out.println("最后通知after");
}
public void around(ProceedingJoinPoint proceedingJoinPoint){
try {
System.out.println("前置通知before");
proceedingJoinPoint.proceed();
System.out.println("后置通知afterRutruning");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("异常通知afterThrowing");
}finally {
System.out.println("最后通知after");
}
}
}
@Service
public class AccountServiceImpl implements AccountService {
@Override
public void transfer() {
System.out.println("转账了");
}
}
applicationContext.xml
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
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">
<!--目标对象,交给ioc-->
<bean id="accountService" class="com.wsl.sercice.impl.AccountServiceImpl"></bean>
<!--通知对象,交给ioc-->
<bean id="myAdvice" class="com.wsl.advice.MyAdvice"></bean>
<!--aop配置-->
<aop:config>
<aop:pointcut id="mypoint" expression="execution(* com.wsl.sercice..*.*(..))"></aop:pointcut>
<aop:aspect ref="myAdvice">
<!--<aop:before method="before" pointcut-ref="mypoint"></aop:before>-->
<!--<aop:after-returning method="afterRutruning" pointcut-ref="mypoint"></aop:after-returning>-->
<!--<aop:after-throwing method="afterThrowing" pointcut-ref="mypoint"></aop:after-throwing>-->
<!--<aop:after method="after" pointcut-ref="mypoint"></aop:after>-->
<aop:around method="around" pointcut-ref="mypoint"></aop:around>
</aop:aspect>
</aop:config>
</beans>
测试:
@RunWith(SpringRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class AccountTest {
@Autowired
AccountService accountService;
@Test
public void test001(){
accountService.transfer();
}
}
二.基于注解的AOP的开发:
(1)项目结构:
开启spring的aop注解支持
MyAdvice将通知对象升级为切面
通知+切点=切面
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class MyAdvice {
// @Before("execution(* com.wsl.service..*.*(..))")
// public void before(){
// System.out.println("前置通知before");
// }
//
// @AfterReturning("execution(* com.wsl.service..*.*(..))")
// public void afterRutruning(){
// System.out.println("后置通知afterRutruning");
// }
//
// @AfterThrowing("execution(* com.wsl.service..*.*(..))")
// public void afterThrowing(){
// System.out.println("异常通知afterThrowing");
// }
//
// @After("execution(* com.wsl.service..*.*(..))")
// public void after(){
// System.out.println("最后通知after");
// }
@Pointcut("execution(* com.wsl.service..*.*(..))")
public void myPontCut(){}
@Around("MyAdvice.myPontCut()")
public void around(ProceedingJoinPoint proceedingJoinPoint){
try {
System.out.println("前置通知before");
proceedingJoinPoint.proceed();
System.out.println("后置通知afterRutruning");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("异常通知afterThrowing");
}finally {
System.out.println("最后通知after");
}
}
}
@Service
public class AccountServiceImpl implements AccountService {
@Override
public void transfer() {
// int i = 9/0;
System.out.println("anno 转账了");
}
}
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
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">
<!--全注解扫描-->
<context:component-scan base-package="com.wsl"></context:component-scan>
<!--aop自动注解配置-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
import com.wsl.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class AccountTest {
@Autowired
AccountService accountService;
@Test
public void Test001(){
accountService.transfer();
}
}
(2)注解配置详解:
切点表达式: 语法与xml一致
如何切面类中,抽取切点表达式:
通知类型:
四大通知:
名称 | 标签 | 说明 |
---|---|---|
前置通知 | @Before | 在切入点方法之前执行 |
后置通知 | @AfterReturning | 在切入点方法正常运行之后执行 |
异常通知 | @AfterThrowing | 在切点方法发生异常的时候执行 |
最终通知 | @After | 无论切入点方法执行时是否有异常,都会执行 |
注意:使用注解时,四大通知同时开启的顺序:
@Before -- > @After --> @AfterReturning(@AfterThrowing)
注解版本的四大通知,单独使用...
环绕通知:
名称 | 标签 | 说明 |
---|---|---|
环绕通知 | @Around | 可以灵活实现四大通知的所有效果 |
(3)纯注解配置:
不适用配置文件:
@Component
@Aspect
public class MyAdvice {
// @Pointcut("execution(* com.wsl.service..*.*(..))")
@Pointcut("execution(* com.wsl.service..*.*(..))")
public void myPontCut(){}
// @Before("execution(* com.wsl.service..*.*(..))")
// public void before(){
// System.out.println("前置通知before");
// }
//
// @AfterReturning("execution(* com.wsl.service..*.*(..))")
// public void afterRutruning(){
// System.out.println("后置通知afterRutruning");
// }
//
// @AfterThrowing("execution(* com.wsl.service..*.*(..))")
// public void afterThrowing(){
// System.out.println("异常通知afterThrowing");
// }
//
// @After("execution(* com.wsl.service..*.*(..))")
// public void after(){
// System.out.println("最后通知after");
// }
@Around("MyAdvice.myPontCut()")
public void around(ProceedingJoinPoint proceedingJoinPoint){
try {
System.out.println("前置通知before");
proceedingJoinPoint.proceed();
System.out.println("后置通知afterRutruning");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("异常通知afterThrowing");
}finally {
System.out.println("最后通知after");
}
}
}
配置文件
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan("com.wsl")
@EnableAspectJAutoProxy
public class SpringConfig {
}
@Service
public class AccountServiceImpl implements AccountService {
@Override
public void transfer() {
// int i = 9/0;
System.out.println("anno 转账了");
}
}
import com.wsl.config.SpringConfig;
import com.wsl.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class AccountTest {
@Autowired
AccountService accountService;
@Test
public void test001(){
accountService.transfer();
}
}
总结:
* 使用@Aspect注解,标注切面类
* 使用@Before等注解,标注通知方法
* 使用@Pointcut注解,抽取切点表达式
* 配置aop自动代理 <aop:aspectj-autoproxy/> 或 @EnableAspectJAutoProxy
三.AOP优化转账案例:
(1)xml实现
在原来项目基础上,添加这个依赖:
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.15</version>
</dependency>
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
相关类:
@Repository
public class AccountDaoImpl implements AccountDao {
@Autowired
private QueryRunner queryRunner;
@Autowired
private ConnectionUtils connectionUtils;
@Override
public void outUser( String outUser, Double money) {
String sql = "update account set money= money-? where name=?";
try {
Connection threadConnection = connectionUtils.getThreadConnection();
queryRunner.update(threadConnection,sql,money,outUser);
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public void inUser(String inUser, Double money) {
String sql = "update account set money= money+? where name=?";
try {
Connection threadConnection = connectionUtils.getThreadConnection();
queryRunner.update(threadConnection,sql,money,inUser);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
public void transfer(String outUser, String inUser, Double money) {
accountDao.outUser(outUser,money);
accountDao.inUser(inUser,money);
}
}
@Component
public class ConnectionUtils {
@Autowired
private DataSource dataSource;
private static final ThreadLocal<Connection> t1= new ThreadLocal<>();
public Connection getThreadConnection(){
Connection connection = t1.get();
if (connection==null){
try {
connection = dataSource.getConnection();
t1.set(connection);
} catch (SQLException e) {
e.printStackTrace();
}
}
return connection;
}
public void removeThreadConnection(){
t1.remove();
}
}
通知对象:环绕通知:
@Component
public class TransactionManager {
@Autowired
private ConnectionUtils connectionUtils;
public void beginTransaction(){
try {
connectionUtils.getThreadConnection().setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
public void commit(){
try {
connectionUtils.getThreadConnection().commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void rollback(){
try {
connectionUtils.getThreadConnection().rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void release(){
try {
connectionUtils.getThreadConnection().setAutoCommit(true);
connectionUtils.getThreadConnection().close();
connectionUtils.removeThreadConnection();
} catch (Exception e) {
e.printStackTrace();
}
}
// 环绕通知
public void aroundTx(ProceedingJoinPoint pjp){
try {
beginTransaction();
pjp.proceed();
commit();
} catch (Throwable throwable) {
throwable.printStackTrace();
rollback();
} finally {
release();
}
}
}
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
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">
<!--开启注解组件扫描-->
<context:component-scan base-package="com.wsl"/>
<!--加载第三方配置-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--druid连接交给ioc容器-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--queryRunner交给ioc容器-->
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
<constructor-arg name="ds" ref="dataSource"></constructor-arg>
</bean>
<!--aop配置-->
<aop:config>
<!--切面-->
<aop:aspect ref="transactionManager">
<!--织入 环绕通知-->
<aop:around method="aroundTx" pointcut="execution(* com.wsl.service..*.*(..))"></aop:around>
</aop:aspect>
</aop:config>
</beans>
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_db
jdbc.username=root
jdbc.password=root
测试
@RunWith(SpringRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class AccountTest {
@Autowired
private AccountService accountService;
@Test
public void test001(){
accountService.transfer("tom","jerry",100d);
}
}
(2)常用注解实现版本:
@Repository
public class AccountDaoImpl implements AccountDao {
@Autowired
private QueryRunner queryRunner;
@Autowired
private ConnectionUtils connectionUtils;
@Override
public void outUser( String outUser, Double money) {
String sql = "update account set money= money-? where name=?";
try {
Connection threadConnection = connectionUtils.getThreadConnection();
queryRunner.update(threadConnection,sql,money,outUser);
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public void inUser(String inUser, Double money) {
String sql = "update account set money= money+? where name=?";
try {
Connection threadConnection = connectionUtils.getThreadConnection();
queryRunner.update(threadConnection,sql,money,inUser);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
public void transfer(String outUser, String inUser, Double money) {
accountDao.outUser(outUser,money);
accountDao.inUser(inUser,money);
}
}
环绕通知:
package com.wsl.tx;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.sql.SQLException;
@Component
@Aspect
public class TransactionManager {
@Autowired
private ConnectionUtils connectionUtils;
public void beginTransaction(){
try {
connectionUtils.getThreadConnection().setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
public void commit(){
try {
connectionUtils.getThreadConnection().commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void rollback(){
try {
connectionUtils.getThreadConnection().rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void release(){
try {
connectionUtils.getThreadConnection().setAutoCommit(true);
connectionUtils.getThreadConnection().close();
connectionUtils.removeThreadConnection();
} catch (Exception e) {
e.printStackTrace();
}
}
// 环绕通知
@Around("execution(* com.wsl.service..*.*(..))")
public void aroundTx(ProceedingJoinPoint pjp){
try {
beginTransaction();
pjp.proceed();
commit();
} catch (Throwable throwable) {
throwable.printStackTrace();
rollback();
} finally {
release();
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.wsl"></context:component-scan>
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
<constructor-arg name="ds" ref="dataSource"></constructor-arg>
</bean>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
@RunWith(SpringRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class AccountTest {
@Autowired
AccountService accountService;
@Test
public void test001(){
accountService.transfer("jerry","tom",100d);
}
}
四。Spring的JdbcTemplate
(1)JdbcTemplate是什么?
JdbcTemplate是Spring的一款用于简化Dao代码的工具包,它底层封装了JDBC技术。
**核心对象**
JdbcTemplate jdbcTemplate = new JdbcTemplate(DataSource dataSource);
核心方法
int update(); 执行增、删、改语句
List<T> query(); 查询多个
T queryForObject(); 查询一个
RowMapper<>(); ORM映射接口
new BeanPropertyRowMapper<>(); 实现ORM映射封装子类
例如:
查询数据库所有账户信息到Account实体中
public class JdbcTemplateTest {
@Test
public void testFindAll() throws Exception {
// 创建核心对象
JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource());
// 编写sql
String sql = "select * from account";
// 执行sql
List<Account> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Account.class));
}
}
(2)入门案例:
依赖坐标:mysql驱动、druid连接池、spring-jdbc、spring-context、junit、spring-junit
<!--依赖管理-->
<dependencies>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--druid连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.15</version>
</dependency>
<!--spring-jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--spring核心-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--spring整合junit-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
工具类连接池:
public class JdbcUtils {
private static DruidDataSource dc = new DruidDataSource();
static {
ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
String driverClass = bundle.getString("jdbc.driver");
String jdbcUrl = bundle.getString("jdbc.url");
String username = bundle.getString("jdbc.username");
String password = bundle.getString("jdbc.password");
dc.setDriverClassName(driverClass);
dc.setUrl(jdbcUrl);
dc.setUsername(username);
dc.setPassword(password);
}
public static Connection getConnection() throws SQLException {
return dc.getConnection();
}
public static DataSource getDataSource(){
return dc;
}
}
新测试代码:
public class JdbcTemplateTest {
// 新增
@Test
public void test01() throws Exception {
// 1.创建JdbcTemplate核心对象
JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource());
// 2.编写sql
String sql = "insert into account(name,money) values(?,?)";
// 3.执行sql
int i = jdbcTemplate.update(sql, "哈哈顶", 1000d);
}
}
查询:
测试案例:
// id查询
@Test
public void test02() throws Exception {
// 1.创建JdbcTemplate核心对象
JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource());
// 2.编写sql
String sql = "select * from account where id = ?";
// 3.执行sql
Account account = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(Account.class), 4);
System.out.println(account);
}
(3)Spring整合JdbcTemplate 以及转账案例
编写AccountDao
import com.wsl.dao.AccountDao;
import com.wsl.domain.Account;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public class AccountDaoImpl implements AccountDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public List<Account> findAll() {
String sql = "select * from account";
List<Account> accountList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Account.class));
return accountList;
}
@Override
public int add(Account account) {
String sql ="insert into account(name,money) values(?,?)";
int update = jdbcTemplate.update(sql, account.getName(), account.getMoney());
return update;
}
@Override
public int delete(Integer aid) {
String sql ="delete from account where id = ? ";
int update = jdbcTemplate.update(sql, aid);
return update;
}
@Override //update score set chinese=60 where id=?
public int update(Account account) {
String sql = "update account set name= ? , money = ? where id= ? ";
int update = jdbcTemplate.update(sql, account.getName(), account.getMoney(), account.getId());
return update;
}
@Override
public Account findById(Integer aid) {
String sql = "select * from account where id = ?";
Account account = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(Account.class), aid);
return account;
}
@Override
public void outUser(String outUser, Double money) {
String sql ="update account set money = money - ? where name = ?";
jdbcTemplate.update(sql,money,outUser);
}
@Override
public void inUser(String inUser, Double money) {
String sql ="update account set money = money + ? where name = ?";
jdbcTemplate.update(sql,money,inUser);
}
}
编写AccountService
import com.wsl.dao.AccountDao;
import com.wsl.domain.Account;
import com.wsl.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import java.util.List;
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
AccountDao accountDao;
@Autowired
private PlatformTransactionManager transactionManager;
@Override
public List<Account> findAll() {
return accountDao.findAll();
}
@Override
public int add(Account account) {
return accountDao.add(account);
}
@Override
public int delete(Integer aid) {
return accountDao.delete(aid);
}
@Override
public int update(Account account) {
return accountDao.update(account);
}
@Override
public Account findById(Integer aid) {
return accountDao.findById(aid);
}
@Override
public void transfer(String outUser, String inUser, Double money) {
DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();
defaultTransactionDefinition.setReadOnly(false);
defaultTransactionDefinition.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = transactionManager.getTransaction(defaultTransactionDefinition);
try{
accountDao.outUser(outUser,money);
accountDao.inUser(inUser,money);
transactionManager.commit(status);
}catch (Exception e){
e.printStackTrace();
transactionManager.rollback(status);
}
}
}
编写Spring配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.wsl"></context:component-scan>
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--<aop:aspectj-autoproxy></aop:aspectj-autoproxy>-->
</beans>
测试:
@RunWith(SpringRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class AccountTest {
@Autowired
AccountService accountService;
@Test
public void test001(){
//查询所有
// List<Account> accountList = accountService.findAll();
// System.out.println(accountList);
//查询id=1的用户
// Account account = accountService.findById(1);
// System.out.println(account);
//新增用户
// Account account1 = new Account();
// account1.setName("beijing");
// account1.setMoney(1200.0);
// accountService.add(account1);
//修改信息
// Account account2 = new Account();
// account2.setName("beijing");
// account2.setMoney(9100.0);
// account2.setId(8);
// accountService.update(account2);
// accountService.delete(10);
accountService.transfer("tom","jerry",200d);
}
}
使用JdbcTemplate,无法操作自定义的事务管理器....
因为spring当时在设计这套工具包的时候,就要求事务交给spring控制
五.Spring的事务:
Spring的事务控制可以分为编程式事务控制和声明式事务控制。
编程式事务
-
就是将业务代码和事务代码放在一起书写,它的耦合性太高,开发中不使用
声明式事务
-
其实就是将事务代码(spring内置)和业务代码隔离开发, 然后通过一段配置让他们组装运行, 最后达到事务控制的目的.
声明式事务就是通过AOP原理实现的.
(1)编程式事务:
PlatformTransactionManager
spring事务管理器的顶级接口,里面提供了我们常用的操作事务的方法
- TransactionStatus getTransaction(TransactionDefinition definition);
功能:获取事务的状态信息
- void commit(TransactionStatus status);
功能:提交事务
- void rollback(TransactionStatus status);
功能:回滚事务
spring事务管理器先定义好规范,真正的执行者需要实现类完成,导入一个坐标 spring-orm
- JpaTransactionManager
会使用sun公司提供的jpa规范(SpringData-jpa)框架事务管理器
- DataSourceTransactionManager
使用 mybatis、jdbc原生、DbUtils、JdbcTemplate框架事务管理
- HibernateTransactionManager
使用hibernate框架事务管理器
TransactionDefinition
spring事务定义参数的接口,比如定义:事务隔离级别、事务传播行为等等
① 事务隔离级别
isolation:事务的隔离级别
* ISOLATION_DEFAULT 使用数据库默认级别
MySQL:ISOLATION_REPEATABLE_READ 可重复读
Oracle:ISOLATION_READ_COMMITTED 读已提交
* ISOLATION_READ_UNCOMMITTED 读未提交
* ISOLATION_READ_COMMITTED 读已提交
* ISOLATION_REPEATABLE_READ 可重复读
* ISOLATION_SERIALIZABLE 串行化
② 事务传播行为
事务传播行为指的就是当一个业务方法【被】另一个业务方法调用时,应该如何进行事务控制。
比如:
方法A、方法B【主语】
方法A去调用方法B
** REQUIRED(默认传播行为)
如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。
如果单独调用方法B时,没有事务,spring就给当前方法创建一个新事物
如果方法A中已经存在了事务,调用方法B时,方法B加方法A的事务中....
** SUPPORTS
支持当前事务,如果当前没有事务,就以非事务方式执行
如果单独调用方法B时没有事务,咱们就以非事务方法运行
如果方法A中已经存在了事务,调用方法B时,方法B加方法A的事务中....
--------------------------------------------------------------------------------------
* MANDATORY
使用当前的事务,如果当前没有事务,就抛出异常
* REQUERS_NEW
新建事务,如果当前在事务中,把当前事务挂起
* NOT_SUPPORTED
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
* NEVER
以非事务方式运行,如果当前存在事务,抛出异常
* NESTED
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作
③ 是否只读
* read-only 只读事务(增 删 改不能使用,只能查询使用)
④ 超时时间
* timeout 默认值是-1,没有超时限制。如果有,以秒为单位进行设置
TransactionStatus
获取spring当前事务运行的状态。
总结:
Spring中的事务控制主要就是通过这三个API实现的
* PlatformTransactionManager 负责事务的管理,它是个接口,其子类负责具体工作
* TransactionDefinition 定义了事务的一些相关参数
* TransactionStatus 代表事务运行的一个实时状态
可以简单的理解三者的关系:事务管理器通过读取事务定义参数进行事务管理,然后会产生一系列的事务状态。
(2)使用编程式事务
配置事务管理器:
<!--事务管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
修改service层代码:
@Service
public class xxxServiceImpl implements xxxService{
@Autowired
private PlatformTransactionManager transactionManager;
public void method() {
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// 设置是否只读,为false才支持事务
def.setReadOnly(false);
// 设置隔离级别
def.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
// 设置事务的传播行为
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// 对事务管理器进行配置
TransactionStatus status = transactionManager.getTransaction(def);
try {
// 业务操作
// 提交事务
transactionManager.commit(status);
} catch (Exception e) {
e.printStackTrace();
// 回滚事务
transactionManager.rollback(status);
}
}
}