实现转账功能,aaa转账给bbb
package cn.tedu.service.impl; import cn.tedu.dao.IAccountDao; import cn.tedu.entity.Account; import cn.tedu.service.IAccountService; import cn.tedu.utils.TransactionManager; import java.util.List; /** * 账户业务层实现类 */ public class AccountServiceImpl1 implements IAccountService { private IAccountDao accountDao; private TransactionManager transactionManager; public TransactionManager getTransactionManager() { return transactionManager; } public void setTransactionManager(TransactionManager transactionManager) { this.transactionManager = transactionManager; } public IAccountDao getAccountDao() { return accountDao; } public void setAccountDao(IAccountDao accountDao) { this.accountDao = accountDao; } @Override public List<Account> findAllAccount() { List<Account> allAccount = accountDao.findAllAccount(); return allAccount; } @Override public Account findAccountById(Integer id) { Account accountById = accountDao.findAccountById(id); return accountById; } @Override public void saveAccount(Account account) { accountDao.saveAccount(account); } @Override public void updateAccount(Account account) { accountDao.updateAccount(account); } @Override public void deleteAccount(Integer id) { accountDao.deleteAccount(id); } @Override//实现转账功能 public void transfer(String sourceName, String targetName, float money) { Account byAccountName = accountDao.findByAccountName(sourceName); byAccountName.setMoney(byAccountName.getMoney() - money); accountDao.updateAccount(byAccountName); int i = 1 / 0;//如果这里发生异常,就会导致,前减了,另一个人却没有加 Account byAccountName1 = accountDao.findByAccountName(targetName); byAccountName1.setMoney(byAccountName1.getMoney()+ money); accountDao.updateAccount(byAccountName1); } }为了解决这个问题,使用了事务类,具体实不用去关心,主要是引出aop思想
加上事务,写上事务管理类
package cn.tedu.utils; import javax.sql.DataSource; import java.sql.Connection; //获取连接的类 public class ConnectionUtils { ThreadLocal<Connection> t1=new ThreadLocal<>(); private DataSource source; public DataSource getSource() { return source; } public void setSource(DataSource source) { this.source = source; } /** * 获取当前线程的连接 */ public Connection getConnection(){ try { Connection conn=t1.get(); if (conn==null){ conn=source.getConnection(); t1.set(conn); } return conn; }catch (Exception e){ throw new RuntimeException(e); } } /** * 把连接和线程解绑 */ public void remove(){ t1.remove(); } } 2. 事务类 1. ```java package cn.tedu.utils; import java.sql.SQLException; /** * 里面包含了,开启事务,关闭事务,回滚事务 */ public class TransactionManager { private ConnectionUtils connectionUtils; public ConnectionUtils getConnectionUtils() { return connectionUtils; } public void setConnectionUtils(ConnectionUtils connectionUtils) { this.connectionUtils = connectionUtils; } public void beginTransaction(){ try { connectionUtils.getConnection().setAutoCommit(false); } catch (SQLException e) { e.printStackTrace(); } } /** * 提交事务 */ public void commit(){ try { connectionUtils.getConnection().commit(); } catch (SQLException e) { e.printStackTrace(); } } /** * 回滚事务 */ public void rollback(){ try { connectionUtils.getConnection().rollback(); } catch (SQLException e) { e.printStackTrace(); } } /** * 关闭事务 */ public void release(){ try { connectionUtils.getConnection().close(); connectionUtils.remove(); } catch (SQLException e) { e.printStackTrace(); } } }为了解决上面那个问题,我们使用了事务类,其实就是jdbc的知识,自己封装的而已,改造后
package cn.tedu.service.impl; import cn.tedu.dao.IAccountDao; import cn.tedu.entity.Account; import cn.tedu.service.IAccountService; import cn.tedu.utils.TransactionManager; import java.util.List; /** * 账户业务层实现类 */ public class AccountServiceImpl implements IAccountService { private IAccountDao accountDao; private TransactionManager transactionManager; public TransactionManager getTransactionManager() { return transactionManager; } public void setTransactionManager(TransactionManager transactionManager) { this.transactionManager = transactionManager; } public IAccountDao getAccountDao() { return accountDao; } public void setAccountDao(IAccountDao accountDao) { this.accountDao = accountDao; } @Override public List<Account> findAllAccount() { try { //开启事务 transactionManager.beginTransaction(); //执行操作 List<Account> allAccount = accountDao.findAllAccount(); //提交事务 transactionManager.commit(); //返回结果 return allAccount; }catch (Exception e){ //回滚事务 transactionManager.rollback(); }finally { //释放连接 transactionManager.release(); } return null; } @Override public Account findAccountById(Integer id) { try { //开启事务 transactionManager.beginTransaction(); //执行操作 Account accountById = accountDao.findAccountById(id); //提交事务 transactionManager.commit(); //返回结果 return accountById; }catch (Exception e){ //回滚事务 transactionManager.rollback(); }finally { //释放连接 transactionManager.release(); } return null; } @Override public void saveAccount(Account account) { try { //开启事务 transactionManager.beginTransaction(); //执行操作 accountDao.saveAccount(account); //提交事务 transactionManager.commit(); //返回结果 }catch (Exception e){ //回滚事务 transactionManager.rollback(); }finally { //释放连接 transactionManager.release(); } } @Override public void updateAccount(Account account) { try { //开启事务 transactionManager.beginTransaction(); //执行操作 accountDao.updateAccount(account); //提交事务 transactionManager.commit(); //返回结果 }catch (Exception e){ //回滚事务 transactionManager.rollback(); }finally { //释放连接 transactionManager.release(); } } @Override public void deleteAccount(Integer id) { try { //开启事务 transactionManager.beginTransaction(); //执行操作 accountDao.deleteAccount(id); //提交事务 transactionManager.commit(); //返回结果 }catch (Exception e){ //回滚事务 transactionManager.rollback(); }finally { //释放连接 transactionManager.release(); } } @Override//实现转账功能 public void transfer(String sourceName, String targetName, float money) { try { //开启事务 transactionManager.beginTransaction(); //执行操作 Account byAccountName = accountDao.findByAccountName(sourceName); byAccountName.setMoney(byAccountName.getMoney()-money); int i=1/0; Account byAccountName1 = accountDao.findByAccountName(targetName); byAccountName1.setMoney(byAccountName1.getMoney()+money); accountDao.updateAccount(byAccountName); accountDao.updateAccount(byAccountName1); //提交事务 transactionManager.commit(); //返回结果 }catch (Exception e){ //回滚事务 transactionManager.rollback(); }finally { //释放连接 transactionManager.release(); } } } //这样我们便不会发送上面那种情况,但是代码过于冗余先看代理的知识
动态代理:
特点:字节码随用随创建,随用随加载
作用:不修改源码的基础上对方法增强
分类:
基于接口的动态代理基于子类的动态代理基于接口的动态代理:
涉及的类:Proxy,提供者JDK官方如何创建代理对象:
使用proxy类中的newProxyInstance方法创建代理对象的要求:
被代理类最少实现一个接口,如果没有则不能使用newProxyInstance方法的参数:
classloder:类加载器:–它是用于加载代理对象字节码的,和被代理对象使用相同的类加载器,固定写法
class[]:字节码数组: --它是用于让代理对象和被代理对象有相同的方法,固定写法
InvocationHandler:用于提供增强代码:—它是让我们写如何代理,我们一般都是写一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的,此接口的实现类都是谁用谁写
例子:
public class Client { public static void main(String[] args) { Producer producer=new Producer(); IProducer iProducer = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(), producer.getClass().getInterfaces(), new InvocationHandler() { /** * 作用:执行被代理对象的任何借口方法都会经过该方法 * @param proxy 代理对象的引用 * @param method 当前执行的方法 * @param args 当前执行方法所需要的参数 * @return 方法执行的返回值 * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //提供增强的代码 float money= (float) args[0]; Object returnValue=null; if ("afterService".equals(method.getName())){ money*=0.8f; returnValue =method.invoke(producer,money); } return returnValue; } }); iProducer.afterService(1000); } }cglib代理,这是没有实现类的情况下
特点:字节码随用随创建,随用随加载
作用:不修改源码的基础上对方法增强
分类:
基于接口的动态代理基于子类的动态代理基于子类的动态代理:
涉及的类:Enhancer,提供者JDK官方如何创建代理对象:
使用Enhancer类中的create方法创建代理对象的要求:
被代理类不能是最终类create方法的参数:
class:字节码:–它是用于指定被代理对象的字节码callback:用于提供增强代码:–它是让我们如何代理,我们一般都是写该接口的子接口实现类:MethodInterceptor例子:
package cglib; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class Client { public static void main(String[] args) { Producer producer=new Producer(); Producer producer1=(Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() { /** * 执行被代理对象的任何方法都会经过该方法 * @param proxy * @param method * @param objects * 以上三个参数和基于接口的动态代理中invoke方法一样的 * @param methodProxy 当前执行方法的代理对象 * @return * @throws Throwable */ @Override public Object intercept(Object proxy, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { //提供增强的代码 float money= (float) objects[0]; Object returnValue=null; if ("afterService".equals(method.getName())){ money*=0.8f; returnValue =method.invoke(producer,money); } return returnValue; } }); producer1.afterService(500); } }修改后:我们只需要一个就可以了
@Test public void proxy() { IAccountService iAccountService = new AccountServiceImpl1(); IAccountService iAccountService1 = (IAccountService) Proxy.newProxyInstance(iAccountService.getClass().getClassLoader(), iAccountService.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object returnValue = null; try { transactionManager.beginTransaction(); returnValue = method.invoke(iAccountService, args); transactionManager.commit(); } catch (Exception e) { transactionManager.rollback(); System.out.println("e"); throw new RuntimeException(e); } finally { transactionManager.release(); } return returnValue; } }); iAccountService1.transfer("aaa","bbb",30); } 创建测试业务类
package cn.tedu; public interface AccountService { /** * 模拟保存用户 */ void saveAccount(); /** * 模拟更新 * @param i */ void updateAccount(int i); /** * 模拟删除 * @return */ int deleteAccount(); } package cn.utils; /** * 用于记录日志的工具类 */ public class Logger { /** * 用于打印日志,计划让其在切入点方法执行之前执行(切入点就是业务层方法) */ public void pringLog(){ System.out.println("Loggrt 类的方法开始进行记录日志了"); } }创建通知类,就是要增强的代码
package cn.utils; /** * 用于记录日志的工具类 */ public class Logger { /** * 用于打印日志,计划让其在切入点方法执行之前执行(切入点就是业务层方法) */ public void pringLog(){ System.out.println("Loggrt 类的方法开始进行记录日志了"); } }项目要导入的jar包
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId><!--解析切入点表达式的--> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency> </dependencies>配置文件
<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" 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-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <!--配置spring的ioc把service对象配置进来--> <bean id="accountService" class="cn.tedu.AccountServiceImpl"></bean> <!--spring基于xml的aop配置步骤 1,把通知bean也交给spring来管理 1. 使用aop:config标签表名开始aop的配置 2. 使用aop:aspect标签表明配置切面 1. id属性:是给前面提供一个唯一标识 2. ref属性:是指通知类bean的id 3. 在aop:aspect标签的内部使用对象标签来配置通知的类型,我们现在实例时让pringLog方法在切入点方法执行之前:所以是前置通知 1. aop:before:标识前置通知 1. method属性:用于指定logger类中哪个方法是前置通知 2. pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强 2. 切入带你表达式的写法: 1. 关键字: execution(表达式) 1. 表达式: 访问修饰符 返回值 包名.包名.包名.....类名.方法名(参数列表) 2. 标准表达式写法: public void com.cn.tedu.AccountServiceImpl.saveAccount() --> <!--配置logger类--> <bean id="logger" class="cn.utils.Logger"/> <!--配置aop--> <aop:config> <!--配置切面--> <aop:aspect id="" ref="logger"> <!--配置通知的类型,并且建立通知方法和切入点方法的关联--> <aop:before method="pringLog" pointcut="execution(public void cn.tedu.AccountServiceImpl.saveAccount())"/> </aop:aspect> </aop:config> </beans>把通知bean也交给spring来管理
使用aop:config标签表名开始aop的配置
使用aop:aspect标签表明配置切面
id属性:是给前面提供一个唯一标识ref属性:是指通知类bean的id在aop:aspect标签的内部使用对象标签来配置通知的类型,我们现在实例时让pringLog方法在切入点方法执行之前:所以是前置通知
aop:before:标识前置通知
method属性:用于指定logger类中哪个方法是前置通知pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强切入带你表达式的写法:
关键字: execution(表达式)
表达式: — 访问修饰符 返回值 包名.包名.包名…类名.方法名(参数列表)标准表达式写法: public void com.cn.tedu.AccountServiceImpl.saveAccount()
全通配写法:
* *..*.*(..)访问修饰符可以省略
void com.cn.tedu.AccountServiceImpl.saveAccount()返回值可以使用通配符 表示任意返回值
* com.cn.tedu.AccountServiceImpl.saveAccount()包名可以使用通配符,标识任意包,但是有几级包,就需要写几个*.
* *.*.*.AccountServiceImpl.saveAccount()包名可以使用…表示当前包及其子包
* *..AccountServiceImpl.saveAccount()类名和方法名都可以使用*
* *..*.*()参数列表: 可以直接写数据类型
基本类型 直接写名称 int引用类型写包名.类名的方式 java.lang.String可以使用通配符表示任意参数,但必须是有参数可以使用…表示有误参数均可,有参数可以是任意数据类型实际开发中切入点表达式的通常写法:切到业务层实现类下的所有方法
cn.tedu.service.imp.*.*(..)通知类型:
前置通知:在切入点方法执行之前执行后置通知:在切入点方法正常执行之后执行(它和异常通知只能执行一个)异常通知:在切入点方法执行产生异常之后执行(它和后置通知只能执行一个)最终通知:无论切入点方法是否正常执行它都会在其后面执行环绕通知测试
aop配置类:和上面不变,就是通知类型变多
package cn.utils; /** * 用于记录日志的工具类 */ public class Logger { /** * 用于打印日志,计划让其在切入点方法执行之前执行(切入点就是业务层方法) */ //前置通知 public void pringLog(){ System.out.println("Loggrt 前置通知"); } //后置通知 public void afterReturning(){ System.out.println("后置通知"); } //异常通知 public void afterThrowingPointLog(){ System.out.println("异常通知"); } //最终通知 public void afterPringLog(){ System.out.println("最终通知"); } }配置文件
<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" 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-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <!--配置spring的ioc把service对象配置进来--> <bean id="accountService" class="cn.tedu.AccountServiceImpl"></bean> <bean id="logger" class="cn.utils.Logger"/> <!--配置aop--> <aop:config> <!--配置切面--> <aop:aspect id="" ref="logger"> <!--配置通知的类型,并且建立通知方法和切入点方法的关联--> <aop:before method="pringLog" pointcut="execution(* *..AccountServiceImpl.*())"/> <!--后置通知--> <aop:after-returning method="afterReturning" pointcut="execution(* *..AccountServiceImpl.*())"/> <!--异常通知`通知--> <aop:after-throwing method="afterThrowingPointLog" pointcut="execution(* *..AccountServiceImpl.*())"/> <!--最终通知通知--> <aop:after method="afterPringLog" pointcut="execution(* *..AccountServiceImpl.*())"/> </aop:aspect> </aop:config> </beans>上面那种过于繁琐
<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" 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-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <!--配置spring的ioc把service对象配置进来--> <bean id="accountService" class="cn.tedu.AccountServiceImpl"></bean> <bean id="logger" class="cn.utils.Logger"/> <!--配置aop--> <aop:config> <!--配置切面--> <aop:aspect id="" ref="logger"> <!--配置通知的类型,并且建立通知方法和切入点方法的关联--> <aop:before method="pringLog" pointcut-ref="pul"/> <!--后置通知--> <aop:after-returning method="afterReturning" pointcut-ref="pul"/> <!--异常通知`通知--> <aop:after-throwing method="afterThrowingPointLog" pointcut-ref="pul"/> <!--最终通知通知--> <aop:after method="afterPringLog" pointcut-ref="pul"/> <!--配置切入点表达式 id用于指定表达式的唯一标识,experssion属性用于指定表达式的内容--> <aop:pointcut id="pul" expression="execution(* *..AccountServiceImpl.*())"/> </aop:aspect> </aop:config> </beans>环绕通知
配置xml
<aop:around method="aroud" pointcut-ref="pul"></aop:around>配置环绕通知类
public Object aroud(ProceedingJoinPoint pro){ Object rtvalue=null; try { Object[] args=pro.getArgs();//得到方法执行所需参数 System.out.println("Logger类中的 方法开始记录日志了: 前置"); rtvalue= pro.proceed(args);//明确调用业务方法(切入点方法) System.out.println("Logger类中的 方法开始记录日志了: 后置"); } catch (Throwable throwable) { System.out.println("Logger类中的 方法开始记录日志了: 异常"); throw new RuntimeException(throwable); }finally { System.out.println("Logger类中的 方法开始记录日志了: 最终"); } return rtvalue; }注解aop
配置文件
<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" 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-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <!--配置spring创建容器时要扫描的包--> <context:component-scan base-package="cn"/> <!--开启aop注解支持--> <aop:aspectj-autoproxy/> </beans>aop通知类
package cn.utils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; /** * 用于记录日志的工具类 */ @Component @Aspect public class Logger { /** * 用于打印日志,计划让其在切入点方法执行之前执行(切入点就是业务层方法) */ @Pointcut("execution(* *..AccountServiceImpl.*())") public void pt1(){} //前置通知 @Before("pt1()") public void pringLog(){ System.out.println("Loggrt 前置通知"); } //后置通知 @AfterReturning("pt1()") public void afterReturning(){ System.out.println("后置通知"); } //异常通知 @AfterThrowing("pt1()") public void afterThrowingPointLog(){ System.out.println("异常通知"); } //最终通知 @After("pt1()") public void afterPringLog(){ System.out.println("最终通知"); } /** * 环绕通知 * spring框架为我们提供了一个接口:proceedingJoinPoing,该接口有一个方法proceed(),此方法就相当于明确的调用了切入点方法 * 该接口可以作为环绕通知的方法参数,在程序执行是,spring框架会为我们提供该接口的实现类供我们使用 * */ @Around("pt1()") public Object aroud(ProceedingJoinPoint pro){ Object rtvalue=null; try { Object[] args=pro.getArgs();//得到方法执行所需参数 System.out.println("Logger类中的 方法开始记录日志了: 前置"); rtvalue= pro.proceed(args);//明确调用业务方法(切入点方法) System.out.println("Logger类中的 方法开始记录日志了: 后置"); } catch (Throwable throwable) { System.out.println("Logger类中的 方法开始记录日志了: 异常"); throw new RuntimeException(throwable); }finally { System.out.println("Logger类中的 方法开始记录日志了: 最终"); } return rtvalue; } }存注解要加上这个
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3bzVeDJ6-1602062746660)(C:\Users\taget\Desktop\spring\SpringAOP.assets\image-20200921225659768.png)]JDBC已经能够满足大部分用户最基本的需求,但是在使用JDBC时,必须自己来管理数据库资源如:获取PreparedStatement,设置SQL语句参数,关闭连接等步骤。
JdbcTemplate是Spring对JDBC的封装,目的是使JDBC更加易于使用。JdbcTemplate是Spring的一部分。JdbcTemplate处理了资源的建立和释放。他帮助我们避免一些常见的错误,比如忘了总要关闭连接。他运行核心的JDBC工作流,如Statement的建立和执行,而我们只需要提供SQL语句和提取结果
作用:
它就是用于和数据库交互的,实现对表的crud操作常用的操作:
导入jar包
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> </dependencies>编写配置类
<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" 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-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <!--配置spring创建容器时要扫描的包--> <context:component-scan base-package="cn"/> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <!--连接数据库必备信息--> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/eesy"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <!--连接数据库必备信息--> <property name="dataSource" ref="dataSource"/> </bean> <bean id="accountDao" class="cn.tedu.dao.AccountDaoImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"/> </bean> </beans>测试常用的增删改查
package cn.tedu.entity.jdbcTemplate; import cn.tedu.entity.Account; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; /** * jdbcTemplate的crud操作 */ public class JdbcTemplateDemo2 { public static void main(String[] args) { ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml"); JdbcTemplate jdbcTemplate = context.getBean("jdbcTemplate", JdbcTemplate.class); //保存 jdbcTemplate.update("insert into account(name,money)values(?,?)","eee",333f); //更新 jdbcTemplate.update("update account set name=?,money=? where id=?","eee",333f); //删除 jdbcTemplate.update("delete from account where id=?",1); //查询所有 // List<Account> query = jdbcTemplate.query("seleclt * from account where money>?", new AccountRowMapper(), 1000f); List<Account> query = jdbcTemplate.query("seleclt * from account where money>?",new BeanPropertyRowMapper<Account>(Account.class), 1000f); //查询一个 List<Account> query1 = jdbcTemplate.query("seleclt * from account where id=?",new BeanPropertyRowMapper<Account>(Account.class), 1000f); System.out.println(query1.isEmpty()?"":query1.get(0)); //查询返回一行一列(使用聚合函数) Long count=jdbcTemplate.queryForObject("select count(*) from account where money>?" ,Long.class,100f); System.out.println(count); } } class AccountRowMapper implements RowMapper<Account>{ @Override public Account mapRow(ResultSet resultSet, int i) throws SQLException { Account account=new Account(); account.setId(resultSet.getInt("id")); account.setName(resultSet.getString("name")); account.setMoney(resultSet.getFloat("money")); return account; } }Spring 框架中,最重要的事务管理的 API 有三个:TransactionDefinition、PlatformTransactionManager 和 TransactionStatus自己去了解。 所谓事务管理,实质上就是按照给定的事务规则来执行提交或者回滚操作。
配置xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:contexnt="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/c" 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-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--配置spring创建容器时要扫描的包--> <context:component-scan base-package="cn"/> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <!--连接数据库必备信息--> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/eesy"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <!--连接数据库必备信息--> <property name="dataSource" ref="dataSource"/> </bean> <!--spring中基于xml的声明式事务控制配置步骤 1,配置事务管理器......这个和上面我们自己写的那个原理差求不多的其实(自我理解) 2,开启sprig对注解事务的支持 3,需要事务支持的地方使用#Transaction事务注解 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--开启spring对注解事务的支持 如果用配置类就是这个注解 @EnableTransactionManagement--> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>service层
package cn.tedu.service.impl; import cn.tedu.dao.IAccountDao; import cn.tedu.entity.Account; import cn.tedu.service.IAccountService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; /** * 账户业务层实现类 */ @Service @Transactional //开启注解 public class AccountServiceImpl1 implements IAccountService { private IAccountDao accountDao; public IAccountDao getAccountDao() { return accountDao; } public void setAccountDao(IAccountDao accountDao) { this.accountDao = accountDao; } @Override @Transactional(propagation = Propagation.SUPPORTS,readOnly = false) //配置读取方法的事务 public Account findAccountById(Integer accountId) { return null; } @Override public void transfer(String sourceName, String targetName, Float money) { System.out.println("ssssss"); Account byAccountName = accountDao.findByAccountName(sourceName); byAccountName.setMoney(byAccountName.getMoney() - money); // int i = 1 / 0; Account byAccountName1 = accountDao.findByAccountName(targetName); byAccountName1.setMoney(byAccountName1.getMoney() + money); accountDao.updateAccount(byAccountName); accountDao.updateAccount(byAccountName1); } }