Spring笔记整理(二)之AOP
IOC回顾
spirng整合连接池
把别人编写的类交给spring管理
-
在外部创建一个jdbc.properties配置文件 这个里面配置各个数据库的信息
-
在spirng的配置文件中,加载外部的jdbc.properties文件
<context:property-placeholder location="classpath:jdbc.properties"/>
-
通过spirng的ioc和di设定连接池的核心对象以及对象的核心属性
ps: ${} 是spring提供的的表达式 针对的就是spring加载了properties之后的数据
<bean id="c3p0" 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.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean>
spring的IOC的注解配置
别人的类还用xml,自己的类都用注解
条件
-
导包 spring-aop.jar
-
开启扫描器
<context:component-scan base-package="cn.dmdream"></context:component-scan>
常用注解
- @Component(“bean的id名称”)
定义在类上 扫描到就会创建该类的实例对象- @Controller(“bean的id名称”) web层的类上
- @service(“bean的id名称”) service层的类上
- @Repository(“bean的id名称”) dao层的类上
- @Value(“属性值”)
定义在属性字段上的 针对的是基本类型和String类型- set的方法可以省略掉
- @Autowired
定义在属性字段上的 针对是对象类型- set的方法可以省略掉
- 会自动去spring容器中找该类的实例对象赋值
- @Qualifier(“指定的对象名称”)
定义在属性字段上的 指定使用该类型下面的哪一个实体对象- 必须要和@Autowired一起使用
- @Scope(“singleton或者prototype”)
全注解的配置
-
条件: 注解类
package cn.dmdream.springconfig; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import com.mchange.v2.c3p0.ComboPooledDataSource; @Configuration // 表示该类是一个注解类 @ComponentScan(basePackages="cn.dmdream") //<context:component-scan base-package="cn.dmdream"></context:component-scan> @PropertySource(value="classpath:jdbc.properties")//<context:property-placeholder location="classpath:jdbc.properties"/> //@Import(value = {DataSourceconfig.class}) public class SpringConfig { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; // 自己创建c3p0连接池 给spring容器 @Bean(name="c3p0") //<bean id="c3p0" class="com.mchange.v2.c3p0.ComboPooledDataSource"> public DataSource createDataSourceC3p0() throws Exception { ComboPooledDataSource ds = new ComboPooledDataSource(); ds.setDriverClass(driver); ds.setJdbcUrl(url); ds.setUser(username); ds.setPassword(password); return ds; } // 4.3以前 要给spring配置一个解析器 来解析 ${} @Bean public static PropertySourcesPlaceholderConfigurer createPropertySourcesPlaceholderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); } }
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://cloud.dmdream.cn:3306/hibernate jdbc.username=root jdbc.password=1234
-
加载不是配置文件了 而是注解类
测试类Demo代码
package cn.dmdream.test; import java.sql.Connection; import java.sql.SQLException; import javax.sql.DataSource; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import cn.dmdream.springconfig.SpringConfig; public class SpringConfigTest { @Test public void test() throws SQLException { // 加载注解类 ApplicationContext context=new AnnotationConfigApplicationContext(SpringConfig.class); /* UserService userService=(UserService)context.getBean("userService"); userService.save();*/ DataSource ds =(DataSource)context.getBean("c3p0"); Connection con = ds.getConnection(); System.out.println(con); } }
spring整合junit
- 导包
- spring-test.jar
- spring-aop.jar
- junit.jar
- 告诉spirng配置文件的位置
- @ContextConfiguration(value=“classpath:applicationContext.xml”)
- 告诉spirng谁加载配置文件
- @RunWith(value =SpringJUnit4ClassRunner.class)
- 分层测试
AOP
一、Spring的AOP概述
-
AOP: 面相切面编程思想
简单理解: 将一些共性的内容进行抽取,在需要用到的地方,以动态代理的方式进行插入
在不修改源码的基础上,还能对源码进行前后的增强 -
底层的技术: 动态代理
-
spring就是把动态代理进行层层封装 诞生出了aop思想
AOP的应用
- 权限拦截
- 日志的输出
- 性能的检测
- 事务管理
aop思想的底层技术: 动态代理
举例
- 目标对象 save
- 代理对象 对目标对象save方法进行增强
两种动态代理的方式
1.JDk动态代理
不用导包,jdk提供好了
proxy
条件: 目标类必须得有接口
@Test
public void test2()
{
// 目标类
final UserImpl user=new UserImpl();
// jdk的动态代理
// 参数一: 和目标类一样的类加载器
// 参数二: 和目标类一样的接口
// 参数三: 增强的业务
User userproxy=(User)Proxy.newProxyInstance(
user.getClass().getClassLoader(),
user.getClass().getInterfaces(),
new InvocationHandler() {
@Override //增强的业务
// 参数一: 固定值
// 参数二: 要增强的方法 (原有的方法)
// 参数三: 方法运行时候需要的参数
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if("save".equals(method.getName()))
{
// 让原有方法执行
// 本身应该调用这个方法的对象
System.out.println("之前增强了...");
method.invoke(user, args);
System.out.println("之后增强了...");
}else
{
// 执行原来的方法
method.invoke(user, args);
}
return null;
}
});
userproxy.save(); // 只要执行,就会执行增强业务方法invoke方法,这个方法里面就是对save方法的增强
userproxy.delete(); // 只要执行,就会执行增强业务方法invoke方法,这个方法里面就是对delete方法的增强
}
User&Impl
package cn.dmdream.domain;
public interface User
{
public void save();
public void delete();
public void update();
public void find();
}
// 带接口的--为了演示jdk动态代理
public class UserImpl implements User
{
@Override
public void save() {
System.out.println("普通的保存方法...");
}
@Override
public void delete() {
System.out.println("普通的删除方法...");
}
@Override
public void update() {
System.out.println("普通的修改方法...");
}
@Override
public void find() {
System.out.println("普通的查询方法...");
}
}
2.CGLIB动态代理
第三方 单用它就必须导包
enhance
条件: 只要有一个目标类即可增强
@Test
public void test3()
{
// 目标类---没有接口
final Person person=new Person();
// CGLIB的方式
// 参数一: 目标类的字节码文件类型 因为用于继承
// 参数二: 增强的业务逻辑
Person p=(Person)Enhancer.create(Person.class,new MethodInterceptor() {
@Override
// 参数一: 代理对象的类型 固定值
// 参数二: 目标类要增强的方法
// 参数三: 方法运行时期需要的参数
// 参数四: 代理方法 忽略
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy arg3) throws Throwable {
if("delete".equals(method.getName()))
{
System.out.println("之前增强....");
method.invoke(person, args);
System.out.println("之后增强....");
}else
{
// 让原有方法执行
method.invoke(person, args);
}
return null;
}
});
p.delete(); // 执行了它 增强业务intercept方法也会执行 这个方法里面就是对delete的增强
p.find();// 执行了它 增强业务intercept方法也会执行 这个方法里面就是对find的增强
}
Person
package cn.dmdream.domain;
// 没有接口--为了演示cglib的动态代理
public class Person
{
public void save() {
System.out.println("普通的保存方法...");
}
public void delete() {
System.out.println("普通的删除方法...");
}
public void update() {
System.out.println("普通的修改方法...");
}
public void find() {
System.out.println("普通的查询方法...");
}
}
3.spring使用的代理方式
- 如果目标类有接口 会默认使用jdk的动态代理
- 如果目标类没有接口 会默认使用CGLIB的动态代理
二、Spring AOP快速入门(全xml配置)
AOP的术语
- 目标对象 要被增强的对象
- 代理对象 增强以后的对象
- 连接点: 可以被增强的方法
- 例如:person里面的save() delete() update() find() 都可以被增强 统称为连接点
- 切入点: 要被增强的方法
- 例如: person里面要开始增强delete方法了 那么delete方法就是切入点
- 通知/增强: 做了增强的那段代码方法
- 只要在原有方法之前和之后进行了增强的代码方法,我们就可以把这些增强的代码方法称之为通知或者增强
- 切面: 切入点+通知/增强=切面
- 里面有要被增强的方法+增强的方法
- 织入: 切入点集成到切面的这一个过程,就叫做织入过程
基于aspectj的AOP的快速入门
-
导包
- 1 AOP联盟 (AOP的一套规范(接口))—从依赖包导入
- 2 Spring-aop.jar(实现了AOP的一套规范)
- 3 aspectj.jar(第三方的–实现了AOP的一套规范)
- 4 spring-aspects.jar (spring整合aspectj)—从核心包导入
-
开发步骤
需求: 对person中的save方法进行增强
-
确定目标类 (目标类中有切入点 —要被增强的方法)
<!-- 目标类 (有切入点 有被增强的方法save) --> <bean id="person" class="cn.dmdream.domain.Person"></bean>
-
确定切面类 (里面有通知/增强 ----增强的那段代码方法)
<!-- 切面类(有通知/增强 有增强方法) --> <bean id="myAspect" class="cn.dmdream.aspectj.MyAspect"></bean>
-
配置织入过程 (将增强方法和被增强方法进行结合)
<!-- 配置织入(增强方法和被增强方法集成在一起) --> <aop:config> <aop:aspect ref="myAspect"><!-- 指定切面类 --> <!-- 原始方式 --> <aop:before method="beforeMethod" pointcut="execution(void cn.dmdream.domain.Person.save())"/> <aop:after-returning method="aftereturningMethod" pointcut="execution(void cn.dmdream.domain.Person.save())"/> <aop:after-returning method="aftereturningMethod" pointcut="execution(void cn.dmdream.domain.Person.save())"/> <!-- 便捷方式 --> <!-- 定义切入点 --> <aop:pointcut expression="execution(void cn.dmdream.domain.Person.save())" id="pointcut1"/> <aop:pointcut expression="execution(void cn.dmdream.domain.Person.delete())" id="pointcut2"/> <aop:pointcut expression="execution(* cn.dmdream.domain.Person.up*(..))" id="pointcut3"/> <aop:pointcut expression="execution(* cn.dmdream.domain.*.find(..))" id="pointcut4"/> <!-- 通过切入点织入 --> <aop:before method="beforeMethod" pointcut-ref="pointcut1"/> <aop:after-returning method="aftereturningMethod" pointcut-ref="pointcut1"/> <aop:after-returning method="aftereturningMethod" pointcut-ref="pointcut2"/> <aop:around method="aroundMethod" pointcut-ref="pointcut3"/> <aop:after-throwing method="throwingMethod" pointcut-ref="pointcut4"/> <aop:after method="afterMethod" pointcut-ref="pointcut4"/> </aop:aspect> </aop:config>
-
AOP的xsd约束(完整版例子)
<?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" 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"> <!-- 目标类 (有切入点 有被增强的方法save) --> <bean id="person" class="cn.dmdream.domain.Person"></bean> <!-- 切面类(有通知/增强 有增强方法) --> <bean id="myAspect" class="cn.dmdream.aspectj.MyAspect"></bean> <!-- 配置织入(增强方法和被增强方法集成在一起) --> <aop:config> <aop:aspect ref="myAspect"> <!-- 定义切入点 --> <aop:pointcut expression="execution(void cn.dmdream.domain.Person.save())" id="pointcut1"/> <aop:pointcut expression="execution(void cn.dmdream.domain.Person.delete())" id="pointcut2"/> <aop:pointcut expression="execution(* cn.dmdream.domain.Person.up*(..))" id="pointcut3"/> <aop:pointcut expression="execution(* cn.dmdream.domain.*.find(..))" id="pointcut4"/> <!-- 原始方式 --> <!-- <aop:before method="beforeMethod" pointcut="execution(void cn.dmdream.domain.Person.save())"/> <aop:after-returning method="aftereturningMethod" pointcut="execution(void cn.dmdream.domain.Person.save())"/> --> <!-- <aop:after-returning method="aftereturningMethod" pointcut="execution(void cn.dmdream.domain.Person.save())"/> --> <!--便捷方式 --> <aop:before method="beforeMethod" pointcut-ref="pointcut1"/> <aop:after-returning method="aftereturningMethod" pointcut-ref="pointcut1"/> <aop:after-returning method="aftereturningMethod" pointcut-ref="pointcut2"/> <aop:around method="aroundMethod" pointcut-ref="pointcut3"/> <aop:after-throwing method="throwingMethod" pointcut-ref="pointcut4"/> <aop:after method="afterMethod" pointcut-ref="pointcut4"/> </aop:aspect> </aop:config> </beans>
-
细节1-切入点语法表达式的抽取
方式一:不定义切入点
<!-- 目标类 (有切入点 有被增强的方法save) -->
<bean id="person" class="cn.dmdream.domain.Person"></bean>
<!-- 切面类(有通知/增强 有增强方法) -->
<bean id="myAspect" class="cn.dmdream.aspectj.MyAspect"></bean>
<!-- 配置织入(增强方法和被增强方法集成在一起) -->
<aop:config>
<aop:aspect ref="myAspect">
<!-- 原始方式 -->
<aop:before method="beforeMethod" pointcut="execution(void cn.dmdream.domain.Person.save())"/>
<aop:after-returning method="aftereturningMethod" pointcut="execution(void cn.dmdream.domain.Person.save())"/>
<aop:after-returning method="aftereturningMethod" pointcut="execution(void cn.dmdream.domain.Person.save())"/>
</aop:aspect>
</aop:config>
方式二:自定义切入点
<!-- 便捷方式 -->
<!-- 定义切入点 -->
<aop:pointcut expression="execution(void cn.dmdream.domain.Person.save())" id="pointcut1"/>
<aop:pointcut expression="execution(void cn.dmdream.domain.Person.delete())" id="pointcut2"/>
<aop:pointcut expression="execution(* cn.dmdream.domain.Person.up*(..))" id="pointcut3"/>
<aop:pointcut expression="execution(* cn.dmdream.domain.*.find(..))" id="pointcut4"/>
<!-- 通过切入点织入 -->
<aop:before method="beforeMethod" pointcut-ref="pointcut1"/>
<aop:after-returning method="aftereturningMethod" pointcut-ref="pointcut1"/>
<aop:after-returning method="aftereturningMethod" pointcut-ref="pointcut2"/>
<aop:around method="aroundMethod" pointcut-ref="pointcut3"/>
<aop:after-throwing method="throwingMethod" pointcut-ref="pointcut4"/>
<aop:after method="afterMethod" pointcut-ref="pointcut4"/>
细节2-切入点语法表达式的书写
execution(void cn.dmdream.domain.Person.save())
void cn.dmdream.domain. Person. save()
返回值 包名/子包名 类名 方法名
*: 代表所有
..: 代表上一层 或者是 方法参数的全匹配
* cn.dmdream.domain.Person.save(..)//最常用
* cn.dmdream.domain.Person.sa*(..)
* cn.dmdream.domain.*.*(..)
* cn.dmdream..*.*(..)
* cn.dmdream..Person.save(..)//最常用
细节3-通知类型
切入点配置和织入过程详细见上面的配置文件
-
前置通知 在之前增强 权限拦截
<aop:pointcut expression="execution(void cn.dmdream.domain.Person.save())" id="pointcut1"/> <aop:before method="beforeMethod" pointcut-ref="pointcut1"/>
// 增强方法 public void beforeMethod() { System.out.println("-----beforeMethod-----"); }
-
后置通知 在之后增强 日志输出
<aop:pointcut expression="execution(void cn.dmdream.domain.Person.delete())" id="pointcut2"/> <aop:after-returning method="aftereturningMethod" pointcut-ref="pointcut2"/>
// 增强方法 public void aftereturningMethod() { System.out.println("----aftereturningMethod---"); }
-
环绕通知 在之前和之后都增强 性能检测
<aop:pointcut expression="execution(* cn.dmdream.domain.Person.up*(..))" id="pointcut3"/> <aop:around method="aroundMethod" pointcut-ref="pointcut3"/>
// 增强方法 public void aroundMethod(ProceedingJoinPoint pdp) throws Throwable // 正在要执行的原有方法 { System.out.println("之前..."); // 原有方法执行一下 pdp.proceed(); // method.invoke(); System.out.println("之后..."); }
-
异常通知 catch{}
<aop:pointcut expression="execution(* cn.dmdream.domain.Person.up*(..))" id="pointcut3"/> <aop:after-throwing method="throwingMethod" pointcut-ref="pointcut4"/>
// 增强方法 public void throwingMethod() { System.out.println("----throwingMethod----"); }
-
最终通知 finally {}
<aop:pointcut expression="execution(* cn.dmdream.domain.*.find(..))" id="pointcut4"/> <aop:after method="afterMethod" pointcut-ref="pointcut4"/>
// 增强方法 public void afterMethod() { System.out.println("--不管你有没有异常,我都出来了---"); }
三、Spring AOP的注解方式
半xml和半注解的方式
别人类用xml <–> 自己的类用注解
如何使用
-
导包 spring-aop.jar
-
开启注解扫描器
<?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" 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="cn.dmdream"></context:component-scan> <!-- 开启注解的动态代理方式 为了识别@Before @AfterReturning --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
自己的类
- Person @Componect(“person”) 目标类
- MyAspect @Componect(“myAspect”) @Aspect切面类
使用注解替代aop织入的xml配置
-
确定谁是切面类 @Aspect
// 切面类--有增强方法 @Component("myAspect") @Aspect public class MyAspect{ ... }
-
切面类下面的增强方法就能使用注解来配置了
条件:先开启动态代理的注解方式
<!-- 开启注解的动态代理方式 为了识别@Before @AfterReturning --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
Demo代码
-
主配置文件(见上面)
-
目标类
package cn.dmdream.domain; import org.springframework.stereotype.Component; // 没有接口--为了演示cglib的动态代理 @Component("person") public class Person { public void save() { System.out.println("普通的保存方法..."); } public void delete() { System.out.println("普通的删除方法..."); } public void update() { System.out.println("普通的修改方法..."); } public void find() { System.out.println("普通的查询方法..."); } }
-
切面类
package cn.dmdream.aspectj; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; // 切面类--有增强方法 @Component("myAspect") @Aspect public class MyAspect { // 增强方法 @Before(value ="execution(* cn.dmdream.domain.Person.save(..))") public void beforeMethod() { System.out.println("-----beforeMethod-----"); } // 增强方法 @AfterReturning(value="execution(* cn.dmdream.domain.Person.delete(..))") public void aftereturningMethod() { System.out.println("----aftereturningMethod---"); } // 增强方法 @Around(value="execution(* cn.dmdream.domain.Person.find(..))") public void aroundMethod(ProceedingJoinPoint pdp) throws Throwable // 正在要执行的原有方法 { System.out.println("之前..."); // 原有方法执行一下 pdp.proceed(); // method.invoke(); System.out.println("之后..."); } // 增强方法 @AfterThrowing(value="execution(* cn.dmdream.domain.Person.update(..))") public void throwingMethod() { System.out.println("----throwingMethod----"); } // 增强方法 @After(value="execution(* cn.dmdream.domain.Person.update(..))") public void afterMethod() { System.out.println("--不管你有没有异常,我都出来了---"); } }
-
测试类
@ContextConfiguration("classpath:applicationContext.xml") @RunWith(SpringJUnit4ClassRunner.class) public class SpringJunit { @Autowired private Person person; @Test public void test() { person.update(); } }
全注解方式
-
得有一个注解类
package cn.dmdream.springconfig; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration // 当前类是注解类 @ComponentScan(basePackages="cn.dmdream") //<context:component-scan base-package="cn.dmdream"></context:component-scan> @EnableAspectJAutoProxy //<aop:aspectj-autoproxy></aop:aspectj-autoproxy> public class SpringConfig { // 目前没有别人的类 }
-
目标类和切面类与上面
半xml半注解方式
相同 -
测试类
package cn.dmdream.demo; 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.SpringJUnit4ClassRunner; import cn.dmdream.domain.Person; import cn.dmdream.springconfig.SpringConfig; //@ContextConfiguration("classpath:applicationContext.xml") // 加载配置文件 @ContextConfiguration(classes=SpringConfig.class) //加载注解类 @RunWith(SpringJUnit4ClassRunner.class) public class SpringJunit { @Autowired private Person person; @Test public void test() { person.save(); } }
四、AOP总结&回顾
Spring的AOP
底层:动态代理
思想:将一些共性的内容进行抽取 在需要用到的地方以动态代理的形式进行插入
在不修改源码的基础上 还能对源码进行前后的增强
底层:企业开发不会自己写 因为全都封装好了
继承 httpServletRequest request; 是tomcat帮你们创建出来的
缺点: 需要知道要继承的父类是谁
装饰者模式
缺点: 需要有接口 save() 100个方法
这个接口下除了要增强的方法以外,别的方法也得实现
动态代理
jdk的动态代理 save() 100个方法
需要有接口 可以指定只增强这个接口下的哪个方法
cglib的动态代理
不需要有接口 也可以指定增强方法
缺点:代码写的多
Spring得到Junit测试不需要开启注解扫描器
spting-test.jar spring-aop.jar junit4.jar
AOP的回顾:
1 导包
AOP联盟
spring-aop.jar
aspectj.jar
spring-aspects.jar
2 编写
1 确定目标类 (里面有切入点 要被增强的方法)
2 确定切面类 (里面有通知/增强 有增强方法)
3 织入的配置 (把增强方法指定在切入点之前,之后,环绕,异常,最终执行)
Spring声明式事务
一、spring的JdbcTemplate
jdbcTemplate是spring提供的dao层用来和数据库数据交互的技术
回顾dao层操作数据库数据的技术
- jdbc+c3p0 任何代码要想操作数据库的数据都得遵循jdbc规范
- dbutils apache组织提供的对jdbc+c3p0的封装
- hibernate 对jdbc+c3p0的封装
- jdbctemplate spring对jdbc+c3p0的封装
- hibernateTemplate spring对hibernate又封装一次
- mybatis 对jdbc+c3p0的封装
- SqlMapClientTemplate sping对mybatis又封装一次
执行效率:A mybatis B dbutils C hibernateTemplate
jdbctemplate和dbutils比较
-
dbutils:apache公司
QueryRunner qr=new QueryRunner(); qr.setDataSource(连接池); String sql="crud"; qr.update(); qr.query();
-
jdbctemplate:Spring公司
jdbctemplate qr=new jdbctemplate(); qr.setDataSource(连接池); String sql="crud"; qr.update(); qr.query();
jdbctemplate的开发步骤
1.导包
- spring-jdbc.jar
- spring-tx.jar
2.配置文件
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"
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">
<!-- spring加载src下的properties文件 -->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!-- c3p0 -->
<bean id="c3p0" 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.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- jdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="c3p0"></property>
</bean>
<!-- accountDao -->
<bean id="accountDao" class="cn.dmdream.daoimpl.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<!-- accountService -->
<bean id="accountService" class="cn.dmdream.serviceImpl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
</beans>
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://cloud.dmdream.cn:3306/spring04?characterEncoding=UTF8
jdbc.username=root
jdbc.password=xxxx
#jdbc.driver=com.mysql.jdbc.Driver
#jdbc.url=jdbc:oracle://localhost:3306/hibernate
#jdbc.username=root
#jdbc.password=1234
#jdbc.driver=com.mysql.jdbc.Driver
#jdbc.url=jdbc:db2://localhost:3306/hibernate
#jdbc.username=root
#jdbc.password=1234
3.JdbcTemplat入门代码
package cn.dmdream.jdbctempalte;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class Demo
{
@Test // 硬编码的方式
public void test1() throws Exception
{
// c3p0
ComboPooledDataSource ds = new ComboPooledDataSource(); //ioc
ds.setDriverClass("com.mysql.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql://localhost:3306/spring04");
ds.setUser("root"); // di
ds.setPassword("1234");
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(ds);
String sql="insert into account values(?,?)";
jdbcTemplate.update(sql, "jack",1000);
}
@Test // ioc+di
public void test2()
{
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
JdbcTemplate jdbcTemplate =(JdbcTemplate)context.getBean("jdbcTemplate");
String sql="insert into account values(?,?)";
jdbcTemplate.update(sql, "rose",1000);
}
}
4.Service代码略
5.Dao层实现类(完整代码)
package cn.dmdream.daoimpl;
import java.util.List;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import cn.dmdream.dao.AccountDao;
import cn.dmdream.domain.Account;
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao
{
/*继承DaoSupport
*
* 1 在appliactionContext.xml文件中 使用set方式注入了 但是AccountDaoImpl没有set方法
* 2 如果自己里面没有找到 要去父类里面找 setJdbcTempalte() 找到了 注入给父类的jdbcTempalte
* 3 父类如果有了 自己子类为什么不能用jdbcTempalte 因为父类private私有化了
* 4 但是父类里面有一个getJdbcTempalte 相当于子类里面也有一个
* 5 就可以在子类中使用getJdbcTempalte的方法 获取到注入好的JdbcTempalte
* */
@Override
public void save() {
String sql = "insert into Account values(?,?)";
this.getJdbcTemplate().update(sql,"周沛3",10000);
/* String sql="insert into account values(?,?)";
getJdbcTemplate().update(sql,"Tom",100000);*/
}
@Override
public void delete() {
String sql = "delete from Account where username=?";
this.getJdbcTemplate().update(sql,"zhoupei");
}
@Override
public void update() {
String sql = "update Account set money=? where username=?";
this.getJdbcTemplate().update(sql, 1000000,"周沛");
}
@Override
public void findAll() {
String sql = "select * from Account";
List<Account> query = this.getJdbcTemplate().query(sql,new BeanPropertyRowMapper<Account>(Account.class));
for (Account account : query) {
System.out.println(account);
}
/*String sql="select * from account";
List<Account> list = getJdbcTemplate().query(sql, new BeanPropertyRowMapper(Account.class));
for (Account account : list) {
System.out.println(account);
}*/
}
@Override
public void findByname() {
String sql = "select * from Account where username = ?";
Account account = this.getJdbcTemplate().queryForObject(sql, new BeanPropertyRowMapper<Account>(Account.class),"周沛");
System.out.println(account);
/*String sql="select * from account where username=?";
Account account= jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper(Account.class),"jack");
System.out.println(account);*/
}
@Override
public void findCount() {
String sql = "select count(*) from Account";
Long long1 = this.getJdbcTemplate().queryForObject(sql, long.class);
System.out.println(long1);
/*String sql="select count(*) from account";
Long l = jdbcTemplate.queryForObject(sql, long.class);
System.out.println(l);*/
}
@Override
protected void checkDaoConfig() throws IllegalArgumentException {
// TODO Auto-generated method stub
}
/*
*
* set方式注入--第一种
*
* private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public void save() {
String sql="insert into account values(?,?)";
jdbcTemplate.update(sql,"Tom",100000);
}
@Override
public void delete() {
String sql="delete from account where username=?";
jdbcTemplate.update(sql,"Tom");
}
@Override
public void update() {
String sql="update account set money=? where username=?";
jdbcTemplate.update(sql, 999,"rose");
}
@Override // 自己做实现
public void findAll() {
String sql="select * from account";
List<Account> list = jdbcTemplate.query(sql, new RowMapper<Account>(){
@Override
public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
// 自己实现
Account account = new Account();
account.setUsername(rs.getString("username"));
account.setMoney(rs.getDouble("money"));
return account;
}});
for (Account account : list) {
System.out.println(account);
}
}
@Override
public void findAll()
{
String sql="select * from account";
List<Account> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper(Account.class));
for (Account account : list) {
System.out.println(account);
}
}
@Override
public void findByname() {
String sql="select * from account where username=?";
Account account= jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper(Account.class),"jack");
System.out.println(account);
}
@Override
public void findCount() {
String sql="select count(*) from account";
Long l = jdbcTemplate.queryForObject(sql, long.class);
System.out.println(l);
}*/
}
6.测试类
package cn.dmdream.test;
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.SpringJUnit4ClassRunner;
import cn.dmdream.service.AccountService;
@ContextConfiguration("classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringJunit
{
@Autowired
private AccountService accountService;
@Test
public void test()
{
//accountService.save(); //增
//accountService.delete(); //删
//accountService.update(); // 改
//accountService.findAll(); //全查--list
//accountService.findByname();//查单个对象
accountService.findCount(); //查总个数
}
}
jdbctemplate的2种注入方式
参考类cn.dmdream.daoimpl.AccountDaoImpl
PS:hibernateTempalte也有这2中方式
-
set方式注入
能使用注解
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { /* * * set方式注入--第一种 * * */ private JdbcTemplate jdbcTemplate; public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } @Override public void save() { String sql="insert into account values(?,?)"; jdbcTemplate.update(sql,"Tom",100000); } @Override public void delete() { String sql="delete from account where username=?"; jdbcTemplate.update(sql,"Tom"); } @Override public void update() { String sql="update account set money=? where username=?"; jdbcTemplate.update(sql, 999,"rose"); } @Override // 自己做实现 public void findAll() { String sql="select * from account"; List<Account> list = jdbcTemplate.query(sql, new RowMapper<Account>(){ @Override public Account mapRow(ResultSet rs, int rowNum) throws SQLException { // 自己实现 Account account = new Account(); account.setUsername(rs.getString("username")); account.setMoney(rs.getDouble("money")); return account; }}); for (Account account : list) { System.out.println(account); } } @Override public void findAll() { String sql="select * from account"; List<Account> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper(Account.class)); for (Account account : list) { System.out.println(account); } } @Override public void findByname() { String sql="select * from account where username=?"; Account account= jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper(Account.class),"jack"); System.out.println(account); } @Override public void findCount() { String sql="select count(*) from account"; Long l = jdbcTemplate.queryForObject(sql, long.class); System.out.println(l); } }
-
继承的方式
不能使用注解
让jdbctemplate继承JdbcDaoSupport,说明
- 在appliactionContext.xml文件中 使用set方式注入了 但是AccountDaoImpl没有set方法
- 如果自己里面没有找到 要去父类里面找 setJdbcTempalte() 找到了 注入给父类的jdbcTempalte
- 父类如果有了 自己子类为什么不能用jdbcTempalte 因为父类private私有化了
- 但是父类里面有一个公有的getJdbcTempalte 相当于子类里面也有一个
- 就可以在子类中使用getJdbcTempalte的方法 获取到注入好的JdbcTempalte
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { /*继承DaoSupport * * 1 在appliactionContext.xml文件中 使用set方式注入了 但是AccountDaoImpl没有set方法 * 2 如果自己里面没有找到 要去父类里面找 setJdbcTempalte() 找到了 注入给父类的jdbcTempalte * 3 父类如果有了 自己子类为什么不能用jdbcTempalte 因为父类private私有化了 * 4 但是父类里面有一个getJdbcTempalte 相当于子类里面也有一个 * 5 就可以在子类中使用getJdbcTempalte的方法 获取到注入好的JdbcTempalte * */ @Override public void save() { String sql = "insert into Account values(?,?)"; this.getJdbcTemplate().update(sql,"周沛3",10000); } @Override public void delete() { String sql = "delete from Account where username=?"; this.getJdbcTemplate().update(sql,"zhoupei"); } @Override public void update() { String sql = "update Account set money=? where username=?"; this.getJdbcTemplate().update(sql, 1000000,"周沛"); } @Override public void findAll() { String sql = "select * from Account"; List<Account> query = this.getJdbcTemplate().query(sql,new BeanPropertyRowMapper<Account>(Account.class)); for (Account account : query) { System.out.println(account); } } @Override public void findByname() { String sql = "select * from Account where username = ?"; Account account = this.getJdbcTemplate().queryForObject(sql, new BeanPropertyRowMapper<Account>(Account.class),"周沛"); System.out.println(account); } @Override public void findCount() { String sql = "select count(*) from Account"; Long long1 = this.getJdbcTemplate().queryForObject(sql, long.class); System.out.println(long1); } @Override protected void checkDaoConfig() throws IllegalArgumentException { } }
使用jdbctempate对数据库数据进行crud操作一些要点
//查询的得到结果集返回
list List<Account> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper(Account.class));
//单个对象查询
Account account= jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper(Account.class),"jack");
//聚合查
Long l = jdbcTemplate.queryForObject(sql, long.class);
二、回顾Spring导包
- 环境
- bean
- cores
- context
- expression
- 日志
- commons-logging
- log4j
- jdbctemplate
- spring-jdbc
- spring-tx
- mysql-connector(依赖)
- c3p0(依赖)
- SpringJunit
- spring-aop
- spring-test
- junit
- 事务
- spring-tx
三、spring的声明式事务
事务回顾
-
事务有什么特性:ACID
-
原子性:一件完成的事情,要不全部成功 要不全部失败
转账: 加钱 减钱
-
一致性:事务的前后,数据总数不发生变化
jack 1000 rose 1000 2000 jack 500 rose 1500 2000
-
持久性:只要事务已完成(提交),数据就会到数据库中
-
隔离性:事务具备隔离性,如果没有隔离性,会发送读取数据的问题
-
-
不具备隔离性的话,会发生什么问题
读取数据的问题
-
脏读:在一个事务中,读取到了另一个事务还没有提交的数据
必须杜绝的 PS:所有的数据库都自动避免的脏读
-
(不可)重复读:在一个事务中,2次读取到的数据内容不一致(update)
可以允许
一个事务读到了另外一个事务提交的数据 ,造成了前后两次查询结果不一致。
-
虚读/幻读:在一个事务中,2次读取到的数据内容不一致(insert)
可以允许
-
-
通过调整数据库的 隔离级别 ,避免以上问题的发生
设置隔离级别
-
read uncommitted(读未提交) 效率最高 安全最低
引发问题: 脏读
-
read committed(读已提交) oracle
解决: 脏读 , 引发: 不可重复读
-
repeatable read(可重复读) mysql
解决: 脏读 、 不可重复读 , 未解决: 幻读
-
serializable(序列化) 安全最高 效率最低
解决: 脏读、 不可重复读 、 幻读。
-
-
事务的编写
-
获取连接
-
通过连接开启事务
con.setAutoCommit(false); con.commit(); con.rollback();
-
过渡——使用AOP来操作事务
如何让spring提供的事务方法在指定的save之前执行,在save之后执行?——AOP
开启事务(spring提供的方法) 增强的方法
save() 切入点
提交事务(spring提供的方法) 增强的方法
- 以前的事务都得自己来编写操作,那spring给我们提供好了一套操作事务的封装,只要拿过来用即可
- spring给我们提供了2种操作事务的方式
- API的方式 —硬编码方式
- 配置文件的方式
API的方式
硬编码方式 可以将提供好的API以代码的方式进行事务的控制 (没人用) 纯编码方式
PlatformTransactionManager
平台事务管理器 spring提供接口 封装事务的方法
-
提交方法
-
回滚方法
-
我们要用只能找这个接口的实现类来用
-
DataSourceTransactionManager,作用于:dbutils jdbcTempalte connnection
是切面类 里面有提交方法 回滚方法 (通知/增强)
-
相比于 HibernateTransactionManager,作用于: hibernate hibernateTemplate session
Hibernate版
-
TransactionDefinition
事务的定义信息对象
如何设定/获取:
-
事务的隔离级别 (默认获取的就是数据库的隔离级别)
-
事务的超时时间 (默认 time=-1 永不超时 )
-
事务的是否只读 (默认 rederOnly=false 可以做任何的crud操作)
-
事务的传播行为:
解决的事情: 事务嵌套事务的问题
应用场景: service: a() b() a方法有事务 b方法也有事务 在a方法中调用b方法 问:使用谁的事务? REQUIRED(默认值): 查看当前是否有事务,如果有事务使用当前的事务,如果没事务给当前创建一个事务 a方法调用b方法: b先看看a有没有事务,如果a没有事务,就为创建一个事务,大家一起玩 如果a有事务,就放弃自己的事务,加入到a的事务中,一起玩 让所有方法都在一个事务中 SUPPORT: 查看当前是否有事务,如果有事务就使用当前的事务,如果没事务就使用非事务 a方法调用b方法: b先看看a有没有事务,如果a有事务,加入到a的事务中一起玩 如果a没有事务,就全部放弃事务,使用非事务执行
TransactionStatus
运行状态对象
-
时时查看事务的运行状态信息
-
查看当前事务是否完成
-
查看是否为新的事务
-
查看是否回滚
。。。
配置文件/注解的方式
xml方式 (重点) 底层就是API的封装 直接以xml方式告诉给sping即可
xml配置的方式
需求: jack给rose转账
1.导包
- spring-tx.jar
- 事务依赖aop
- AOP联盟
- spring-aop.jar
- aspectj.jar
- spring-aspects.jar
2.编码
-
确定目标类 (TranFerServiceImpl --tranfer)
-
确定切面类 (用人家Spring提供的 因为spring有一个类,里面都是事务的方法)
-
DataSourceTransactionManager
- 提交
- 回滚
<!-- 切面类 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="c3p0"></property> </bean>
-
增强方法:都是关于事务的
-
细节: 得为配了这些事务增强方法的tanfer配置一些事务参数
- 是否只读
- 超时时间
- 传播行为
<!-- 配置DataSourceTransactionManager里面事务方法的一些参数 不写 该方法使用的事务参数都是默认值--> <tx:advice transaction-manager="transactionManager" id="txadvice"> <tx:attributes> <!-- 指定方法名称:是业务核心方法 read-only:是否是只读事务。默认false,不只读。 isolation:指定事务的隔离级别。默认值是使用数据库的默认隔离级别。 propagation:指定事务的传播行为。 timeout:指定超时时间。默认值为:-1。永不超时。 rollback-for:用于指定一个异常,当执行产生该异常时,事务回滚。产生其他异常,事务不回滚。没有默认值,任何异常都回滚。 no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时,事务回滚。没有默认值,任何异常都回滚。 --> <tx:method name="*" read-only="false" propagation="REQUIRED"/> <tx:method name="find*" read-only="true" propagation="SUPPORTS"/> <tx:method name="tranfer"/> </tx:attributes> </tx:advice>
-
-
配置织入
-
专门针对事务的标签
-
指定那个事务用于那个切入点
<!-- 织入 --> <aop:config> <aop:pointcut expression="execution(* cn.dmdream.serviceimpl.TranFerServiceImpl.tranfer(..))" id="pointcut"/> <!-- 针对事务的配置标签 --> <aop:advisor advice-ref="txadvice" pointcut-ref="pointcut"/> </aop:config>
-
-
完整配置文件
<?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/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加载src下的properties文件 --> <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder> <!-- c3p0 --> <bean id="c3p0" 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.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <!-- jdbcTemplate --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="c3p0"></property> </bean> <!-- tranFerDao --> <bean id="tranFerDao" class="cn.dmdream.daoimpl.TranFerDaoImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"></property> </bean> <!-- tranFerService 目标类 --> <bean id="tranFerService" class="cn.dmdream.serviceimpl.TranFerServiceImpl"> <property name="tranFerDao" ref="tranFerDao"></property> </bean> <!-- 切面类 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="c3p0"></property> </bean> <!-- 配置DataSourceTransactionManager里面事务方法的一些参数 不写 该方法使用的事务参数都是默认值 --> <tx:advice transaction-manager="transactionManager" id="txadvice"> <tx:attributes> <tx:method name="tranfer" /> </tx:attributes> </tx:advice> <!-- 织入 --> <aop:config> <aop:pointcut expression="execution(* cn.dmdream.serviceimpl.TranFerServiceImpl.tranfer(..))" id="pointcut"/> <!-- 针对事务的配置标签 --> <aop:advisor advice-ref="txadvice" pointcut-ref="pointcut"/> </aop:config> </beans>
简短总结
导包:
spring-tx.jar
配置在指定的方法前后用事务 (AOP)
AOP导包:
AOP联盟
spring-aop.jar
spring-aspets.jar
aspectj.jar
配置:
1 目标类:tranFerService 里面有切入点 (tranfer)
2 切面类 DataSourceTransactionManager 里面有事务的增强方法
细节1:为使用 DataSourceTransactionManager里面的事务方法配置一些事务的参数
3 配置织入
细节2: 使用事务单独的标签来配置
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
半注解的方式
xml+注解(企业开发)
别人的 用xml 自己的 用注解
-
开启注解扫描
<!-- 开启注解扫描器 --> <context:component-scan base-package="cn.dmdream"></context:component-scan>
-
事务的注解2步
-
指定开启事务的注解 告诉spirng使用的事务方法是谁的方法
<!-- 开启事务的注解配置 告诉使用的是哪个类下的事务,PlatformTransactionManager是DataSourceTransactionManager的父类 --> <tx:annotation-driven transaction-manager="platformTransactionManager"/>
-
将platformTransactionManager里面的事务方法给目标类的切入点方法增强
@Transactional//(切入点)在方法上或则是类上配置
比如:给Service中的方法增强
@Service("tranFerService") @Transactional public class TranFerServiceImpl implements TranFerService{}
-
-
以上的两步操作代替了
-
事务(增强方法)配置
<!-- platformTransactionManager是切面类 --> <tx:advice transaction-manager="platformTransactionManager" id="txadvice"> <tx:attributes> <!-- 给使用事物的这个方法配置一些事务的参数 --> <tx:method name="*" /> </tx:attributes> </tx:advice>
-
配置织入过程
<aop:config> <!-- 配置方法和切入点 --> <aop:pointcut expression="execution(* cn.dmdream.service.TransferServiceImpl.transfer(..))" id="pointcut1"/> <aop:advisor advice-ref="txadvice" pointcut-ref="pointcut1" /> </aop:config>
-
Demo参考
完整配置文件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: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/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加载src下的properties文件 -->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!-- c3p0 -->
<bean id="c3p0" 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.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- jdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="c3p0"></property>
</bean>
<!-- 切面类 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="c3p0"></property>
</bean>
<!-- 自己的类 -->
<!-- 开启注解扫描器 -->
<context:component-scan base-package="cn.dmdream"></context:component-scan>
<!-- 开启事务的注解配置 告诉使用的是哪个类下的事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://cloud.dmdream.cn:3306/spring04?characterEncoding=UTF8
jdbc.username=root
jdbc.password=xxxx
Dao省略
Service
package cn.dmdream.serviceimpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import cn.dmdream.dao.TranFerDao;
import cn.dmdream.service.TranFerService;
@Service("tranFerService")
@Transactional
public class TranFerServiceImpl implements TranFerService
{
@Autowired
private TranFerDao tranFerDao;
public void tranfer(String toUser,String inUser,double money)
{
// 减钱
tranFerDao.toMoney(toUser,money);
//int i=1/0;
// 加钱
tranFerDao.inMoney(inUser,money);
}
}
测试类
package cn.dmdream.test;
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.SpringJUnit4ClassRunner;
import cn.dmdream.service.TranFerService;
@ContextConfiguration("classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringJunit
{
@Autowired
private TranFerService tranFerService;
@Test
public void test()
{
tranFerService.tranfer("周沛", "周沛3", 10000);
}
}
全注解的方式
了解即可
条件: 需要注解类
-
@EnableTransactionManagement
代替了
<tx:annotation-driven transaction-manager="platformTransactionManager"/>
-
在方法的形参使用注解@Qualifier(“c3p0”)
public JdbcTemplate createJdbcTemplate(@Qualifier(“c3p0”) DataSource ds) // 使用注解注入对象
注解类完整代码
其它设置和半xml方式一样
SpringConfig.java
package cn.dmdream.springconfig;
import java.beans.PropertyVetoException;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.mchange.v2.c3p0.ComboPooledDataSource;
@Configuration
@ComponentScan(basePackages="cn.dmdream")
@EnableTransactionManagement //<tx:annotation-driven transaction-manager="transactionManager"/>
public class SpringConfig
{
// 创建出来c3p0 给spring
@Bean(name="c3p0")
public DataSource createDataSourceC3p0() throws PropertyVetoException
{
ComboPooledDataSource ds = new ComboPooledDataSource(); //ioc
ds.setDriverClass("com.mysql.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql://localhost:3306/spring04");
ds.setUser("root"); // di
ds.setPassword("1234");
return ds;
}
@Bean(name="jdbcTemplate")
public JdbcTemplate createJdbcTemplate(@Qualifier("c3p0") DataSource ds) // 使用注解问spring要
{
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(ds);
return jdbcTemplate;
}
@Bean(name="transactionManager")
public DataSourceTransactionManager createDataSourceTransactionManager(@Qualifier("c3p0") DataSource ds) // 使用注解问spring要
{
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(ds);
return dataSourceTransactionManager;
}
}