详解Spring框架入门

作者:佳先森 时间:2023-08-14 12:56:14 

目录
  • 一、什么是Spring

  • 二、什么是IOC

  • 三、快速搭建框架环境

  • 四、spring之依赖注入

  • 五、详解Spring框架的IOC之注解方式

  • 七、Spring之JDBC

  • 八、Spring之事务

  • 九、Spring框架的事务管理之编程式的事务管理

  • 十、Spring框架的事务管理之声明式事务管理,即通过配置文件来完成事务管理(AOP思想)

一、什么是Spring

Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架。
◆目的:解决企业应用开发的复杂性

◆功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能

◆范围:任何Java应用

二、什么是IOC

控制反转(Inversion of Control,英文缩写为IoC)把创建对象的权利交给框架,是框架的重要特征,并非面向对象编程的专用术语。它包括依赖注入和依赖查找。传统的业务层,当需要资源时就在该业务层new资源,这样耦合性(程序之间相互依赖关联)较高。现在将new的部分交给spring,做到高内聚低耦合。简而言之:原先是每当调用dao层或service层方法时,由app来new,现在是将new的权利交给spring,要什么资源从spring中获取!

三、快速搭建框架环境

1.下载框架所需的依赖jar包

 spring官网为:http://spring.io/

下载jar包:   http://repo.springsource.org/libs-release-local/org/springframework/spring

2.导入基本jar包

详解Spring框架入门

其实基本核心jar有beans;context;core;expression包,其他是依赖log4j日志。当然spring的jar不止这些,后期慢慢加上。

3.配置log4j配置文件

日志文件定义在src目录下


### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c\:mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### set log levels - for more verbose logging change 'info' to 'debug' ###

log4j.rootLogger=info, stdout

4.测试日志文件是否部署成功


package com.clj.demo1;

import org.apache.log4j.Logger;
import org.junit.Test;

/**
* 演示日志用法
* @author Administrator
*
*/
public class Demo1 {
//创建日志类
private Logger log=Logger.getLogger(Demo1.class);
@Test
public void run1(){
 //可以将log4j.rootLogger属性中的info改为off则不会再控制台显示
 log.info("执行了");
}
}

5.定义一个接口和实现类

接口:


package com.clj.demo2;

public interface UserService {
public void sayHello();
}

实现类


package com.clj.demo2;

public class UserServiceImpl implements UserService{
private String name;

public String getName() {
 return name;
}
public void setName(String name) {
 this.name = name;
}
public void init(){
 System.out.println("初始化。。");
}
public void sayHello() {
 System.out.println("Hello Spring"+"\t"+name);
}
public void destory(){
 System.out.println("销毁。。");
}

}

6.定义spring专属的配置文件

定义名为applicationContext.xml,位置为src下,与日志文件同目录,导入相对应的约束,并将实现类注入到配置文件中,刚开始入门,使用bean约束


<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
 http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans.xsd">
 <!-- 使用bean标签
  1.id值唯一(必写)
 2.注意:class为实现类路径,不是接口(必写)
 3.init-method核心方法执行之前初始化工作(选写)
 4.destroy-method核心方法执行之后初始化工作(选写)-->
 <bean id="userService" class="com.clj.demo2.UserServiceImpl" init-method="init" destroy-method="destory">
  <property name="name" value="佳先森"></property>
 </bean>
</beans>

7.测试


public class Demo1 {
/**
 * 原始方式
 */
@Test
public void run(){
 //创建实现类
 UserServiceImpl s=new UserServiceImpl();
 s.setName("佳先森");
 s.sayHello();
}
/**
 * 老的工厂版本BeanFactory
 * 旧的工厂不会创建配置文件对象
 */
@Test
public void run2(){
 BeanFactory factory=new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
 UserService us=(UserService)factory.getBean("userService");
 us.sayHello();
}
/**
 * 使用spring框架IOC方式
 * 新版本factory创建启动服务器会创建配置文件对象,再次调用时无需加载工厂
 */
@Test
public void run3(){
 //创建工厂,加载核心配置文件(ClassPathXmlApplicationContext从src下找)
 ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
 //从工厂中获取到对象(配置文件中的id值,这里用了多态)
 UserService usi=(UserService) ac.getBean("userService");
 //调用对象的方法执行
 usi.sayHello();
}
/**
 * 演示destroy-method方法
 * bean摧毁方法不会自动执行
 * 除非scope= singleton或者web容器中会自动调用,但是main函数或测试用例需要手动调用(需要使用ClassPathXmlApplicationContext的close()方法)
 */
@Test
public void run4(){
 //创建工厂,加载核心配置文件(ClassPathXmlApplicationContext从src下找)
 ClassPathXmlApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
 //从工厂中获取到对象(配置文件中的id值,这里用了多态)
 UserService usi=(UserService) ac.getBean("userService");
 //调用对象的方法执行
 usi.sayHello();
 //ApplicationContext实现类提供close方法,将工厂关闭就可执行destory-method方法
 ac.close();
}
}

其中旧工厂与新工厂的区别

* BeanFactory和ApplicationContext的区别

* BeanFactory               -- BeanFactory采取延迟加载,第一次getBean时才会初始化Bean

* ApplicationContext      -- 在加载applicationContext.xml时候就会创建具体的Bean对象的实例,还提供了一些其他的功能

 * 事件传递

 * Bean自动装配

* 各种不同应用层的Context实现

总结:这是个最基本的demo,是将实现类配置到了spring配置文件中,每次启动服务器时,就会加载配置文件,从而实例化了实现类

四、spring之依赖注入

1、什么是依赖注入?

Spring 能有效地组织J2EE应用各层的对象。不管是控制层的Action对象,还是业务层的Service对象,还是持久层的DAO对象,都可在Spring的 管理下有机地协调、运行。Spring将各层的对象以松耦合的方式组织在一起,Action对象无须关心Service对象的具体实现,Service对 象无须关心持久层对象的具体实现,各层对象的调用完全面向接口。当系统需要重构时,代码的改写量将大大减少。依赖注入让bean与bean之间以配置文件组织在一起,而不是以硬编码的方式耦合在一起。理解依赖注入

依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念。具体含义是:当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在 传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在Spring里,创建被调用者的工作不再由调用者来完成,因此称为控制反转;创建被调用者 实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为依赖注入。

不管是依赖注入,还是控制反转,都说明Spring采用动态、灵活的方式来管理各种对象。对象与对象之间的具体实现互相透明。

2. IOC和DI的概念

* IOC -- Inverse of Control,控制反转,将对象的创建权反转给Spring!!

* DI -- Dependency Injection,依赖注入,在Spring框架负责创建Bean对象时,动态的将依赖对象注入到Bean组件中!!

3.演示

对于类成员变量,常用的注入方式有两种

属性set方法注入和构造方法注入

先演示第一种:属性set方法注入

1)持久层


package com.clj.demo3;

public class CustomerDaoImpl {
 public void save(){
   System.out.println("我是持久层的Dao");
 }
}

2)业务层

注意:此时是想将持久层注入到业务层,将创建持久层实例权利交给框架,条件是业务层必须提供持久层的成员属性和set方法


package com.clj.demo3;
/**
* 依赖注入之将dao 层注入到service层
* @author Administrator
*
*/
public class CustomerServiceImpl{
 //提供成员属相,提供set方法
 private CustomerDaoImpl customerDao;

public void setCustomerDao(CustomerDaoImpl customerDao) {
   this.customerDao = customerDao;
 }

public void save(){
   System.out.println("我是业务层的service...");
   //1.原始方式
   //new CustomerDaoImpl().save();

//2.spring 之IOC方式
   customerDao.save();
 }
}

 3)配置文件配置


<!-- 演示依赖注入 -->
  <bean id="customerDao" class="com.clj.demo3.CustomerDaoImpl"/>
  <bean id="customerService" class="com.clj.demo3.CustomerServiceImpl">
      <!-- 将Dao注入到service层 -->
     <property name="customerDao" ref="customerDao"></property>
  </bean>

4)测试


/**
  * spring 依赖注入方式
  * 将dao层注入到service层
  */
 @Test
 public void run2(){
   //创建工厂,加载配置文件,customerService被创建,从而也创建了customerDao
   ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
   CustomerServiceImpl csi=(CustomerServiceImpl) context.getBean("customerService");
   csi.save();
 }

第二种:构造方法注入

1)pojo类并提供构造方法


package com.clj.demo4;
/**
* 演示的构造方法的注入方式
* @author Administrator
*
*/
public class Car1 {
 private String cname;
 private Double price;
 public Car1(String cname, Double price) {
   super();
   this.cname = cname;
   this.price = price;
 }
 @Override
 public String toString() {
   return "Car1 [cname=" + cname + ", price=" + price + "]";
 }

}

2)配置文件配置


<!-- 演示构造方法注入方式 -->
  <bean id="car1" class="com.clj.demo4.Car1">
    <!-- 写法一<constructor-arg name="cname" value="宝马"/>
    <constructor-arg name="price" value="400000"/> -->
    <!--写法二 -->
    <constructor-arg index="0" value="宝马"/>
    <constructor-arg index="1" value="400000"/>
   </bean>

3)测试


@Test
 public void run1(){
   ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
   Car1 car=(Car1) ac.getBean("car1");
   System.out.println(car);
 }

拓展:构造方法之将一个对象注入到另一个对象中

1)pojo类:目的:将上列中的车注入到人类,使之成为其中一个属性,则必须在此类中提供车的成员属性,并提供有参构造方法


package com.clj.demo4;

public class Person {
 private String name;
 private Car1 car1;
 public Person(String name, Car1 car1) {
   super();
   this.name = name;
   this.car1 = car1;
 }
 @Override
 public String toString() {
   return "Person [name=" + name + ", car1=" + car1 + "]";
 }
}

2)配置文件


<!-- 构造方法之将一个对象注入到另一个对象-->
  <bean id="person" class="com.clj.demo4.Person">
    <constructor-arg name="name" value="佳先森"/>
    <constructor-arg name="car1" ref="car1"/>
  </bean>

4.如何注入集合数组

1)定义pojo类


package com.clj.demo4;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

/**
* 演示集合注入的方式
* @author Administrator
*
*/
public class User {
 private String[] arrs;
 private List<String> list;
 private Set<String> sets;
 private Map<String,String> map;
 private Properties pro;

public void setPro(Properties pro) {
   this.pro = pro;
 }

public void setSets(Set<String> sets) {
   this.sets = sets;
 }

public void setMap(Map<String, String> map) {
   this.map = map;
 }

public void setList(List<String> list) {
   this.list = list;
 }

public void setArrs(String[] arrs) {
   this.arrs = arrs;
 }

@Override
 public String toString() {
   return "User [arrs=" + Arrays.toString(arrs) + ", list=" + list
       + ", sets=" + sets + ", map=" + map + ", pro=" + pro + "]";
 }
}

2)配置文件


<!-- 注入集合 -->
  <bean id="user" class="com.clj.demo4.User">
    <!-- 数组 -->
    <property name="arrs">
      <list>
        <value>数字1</value>
        <value>数字2</value>
        <value>数字3</value>
      </list>
    </property>
    <!-- list集合 -->
    <property name="list">
      <list>
        <value>金在中</value>
        <value>王杰</value>
      </list>
    </property>
    <!-- set集合 -->
    <property name="sets">
      <set>
        <value>哈哈</value>
        <value>呵呵</value>
      </set>
    </property>
    <!-- map集合 -->
    <property name="map">
      <map>
        <entry key="aa" value="rainbow"/>
        <entry key="bb" value="hellowvenus"/>
      </map>
    </property>
    <!-- 属性文件 -->
    <property name="pro">
      <props>
        <prop key="username">root</prop>
        <prop key="password">123</prop>
      </props>
    </property>
  </bean>

3)测试


/**
  * 测试注入集合
  */
 @Test
 public void run3(){
   ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
   User user= (User) ac.getBean("user");
   System.out.println(user);
 }

5.怎么分模块开发

在主配置文件加入<import>标签(假如此时在com.clj.test包下定义了一个配置文件applicationContext2.xml)


<!-- 分模块开发之引入其他配置文件 -->
  <import resource="com/clj/test/applicationContext2.xml"/>

五、详解Spring框架的IOC之注解方式

1、入门

1).导入jar包

除了先前6个包,玩注解还需一个spring-aop包

详解Spring框架入门

2).持久层和实现层(这里忽略接口)

持久层


package com.clj.demo1;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
/**
* UserDaoImpl交给IOC的容器管理
* @author Administrator
*
*/
public class UserDaoImpl implements UserDao{

@Override
 public void save() {
   System.out.println("保存客户。。");

}

}

业务层


package com.clj.demo1;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

public class UserServiceImpl implements UserService{

@Override
 public void sayHello() {
   System.out.println("Hello spring");
 }
}

3).定义配置文件

此时约束条件需添加context约束,并添加组件扫描


<?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"> <!-- bean definitions here -->
 <!-- 开启注解扫面 :base-package指定扫面对 包-->
 <context:component-scan base-package="com.clj.demo1"/>
</beans>

4)在实现类中添加注解


/**
* 组件注解,可以用来标记当前的类
* 类似<bean id="userService" class="com.clj.demo1.UserServiceImpl">
* value表示给该类起个别名
*/
@Component(value="userService")
public class UserServiceImpl implements UserService{
     //省略
}

5)编写测试


 /**
  * 注解方式
  */
 @Test
 public void run2(){
   ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
   UserService us=(UserService) ac.getBean("userService");
   us.sayHello();
 }

2.关于bean管理常用属性

1. @Component:组件.(作用在类上)  最原始的注解,所有需要注解的类都写这个没问题,他是通用的

2. Spring中提供@Component的三个衍生注解:(功能目前来讲是一致的)
    * @Controller       -- 作用在WEB层
    * @Service          -- 作用在业务层
    * @Repository       -- 作用在持久层
    * 说明:这三个注解是为了让标注类本身的用途清晰,Spring在后续版本会对其增强

3. 属性注入的注解(说明:使用注解注入的方式,可以不用提供set方法)
    * 如果是注入的普通类型,可以使用value注解
    * @Value             -- 用于注入普通类型
    * 如果注入的是对象类型,使用如 * 解
        * @Autowired        -- 默认按类型进行自动装配   匹配的是类型,与注入类的类名无关
            * 如果想按名称注入
            * @Qualifier    -- 强制使用名称注入            必须与Autowired一起用,指定类名,与注入的类名有关
        * @Resource         -- 相当于@Autowired和@Qualifier一起使用
        * 强调:Java提供的注解
        * 属性使用name属性

4. Bean的作用范围注解

    * 注解为@Scope(value="prototype"),作用在类上。值如下:

        * singleton     -- 单例,默认值

        * prototype     -- 多例

5. Bean的生命周期的配置(了解)

    * 注解如下:

        * @PostConstruct    -- 相当于init-method

        * @PreDestroy       -- 相当于destroy-method

1.演示属性对象注解

条件:采用扫描的方式将属性(name)和对象(userDaoImpl)注入到业务层中

1)持久层开启注解扫描Repository


//@Component(value="userDao")通用类注解
@Repository(value="ud")
public class UserDaoImpl implements UserDao{
 @Override
 public void save() {
   System.out.println("保存客户。。");  
 }
}

2)业务层针对属性和对象提供注解


package com.clj.demo1;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* 组件注解,可以用来标记当前的类
* 类似<bean id="userService" class="com.clj.demo1.UserServiceImpl">
* value表示给该类起个别名
*/
//@Scope(value="grototype")多列的(singletype为单列)
@Component(value="userService")
public class UserServiceImpl implements UserService{
 //属性注解:相当于给name属性注入指定的字符串,setName方法可以省略不写
 @Value(value="佳先森")
 private String name;

/**
  * 引用注入方式一:Autowired()
  * 引用注入方式二:Autowired()+Qualifier
  * 引用注入方式三:@Resource(name="userDao") java方式,按名称识别注入
  */
 //Autowired()按类型自动装配注入(缺点:因为是按类型匹配,所以不是很准确)
 @Autowired()
 @Qualifier(value="ud") //按名称注入,得与Autowired一起用,两者一起能指定类
 private UserDao userDao;
 //注意Qualifier中的value是指定UserDaoImpl类名顶上的注解名,也可以指定配置文件中bean的id名

/*public void setName(String name) {
   this.name = name;
 }*/

@Override
 public void sayHello() {
   System.out.println("Hello spring"+name);
   userDao.save();
 }
 //@PostConstruct标签用于action生命周期中初始化的注解
 @PostConstruct
 public void init(){
   System.out.println("初始化...");
 }
}

3)配置文件只需要开启全部扫描即可


<?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"> <!-- bean definitions here -->
 <!-- 开启注解扫面 :base-package指定扫面对 包-->
 <context:component-scan base-package="com.clj.demo1"/>
</beans>

注意:至于集合还是推荐使用配置文件方式

2.Spring框架整合JUnit单元测试

1)添加单元测试所需依赖包spring-test.jar

详解Spring框架入门

注意:基于myeclipes自带Junit环境,但是有时因为版本问题,可能需要比较新的Junit环境,这里我在网上下了一个教新的 Junit-4.9的jar包,如果myeclipes较新的话无须考虑

2)编写测试类,添加相对应的注解

@RunWith与@ContextConfiguration(此是用于加载配置文件,因为默认从WebRoot路径为一级目录,加上此是认定src为一级目录)


package com.clj.demo2;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.clj.demo1.UserService;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo2 {
 @Resource(name="userService")
 private UserService userService;
 @Test
 public void run1(){
   userService.sayHello();
 }
}

六.spring框架之AOP

1.什么是AOP

        * 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,功能模块化

        * AOP是一种编程范式,隶属于软工范畴,指导开发者如何组织程序结构

        * AOP最早由AOP联盟的组织提出的,制定了一套规范.Spring将AOP思想引入到框架中,必须遵守AOP联盟的规范

        * 通过预编译方式和运行期 * 实现程序功能的统一维护的一种技术

        * AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型

        * 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率

     AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)

2. 为什么要学习AOP

        * 可以在不修改源代码的前提下,对程序进行增强!!(为固定的方法生成一个代理,在访问该方法之前,先进入代理,在代理中,可以编写更多的功能,使之方法的功能更强,使得程序进行增        强)

Aop:面向切面编程,将一切事模块化,每个模块比较独立,模块可以共用(相同的),不同的格外自定义。用此替代传统的面向纵向编程,提高程序的可重用性

3.AOP的实现(实现原理)

Aop的实现包含两种代理方式<1>实现类接口:采用JDK * <2>未实现类接口:采用CGLIB *

   1.实现JDK *

      1)定义持久层接口实现类


package com.clj.demo3;

public interface UserDao {
 public void save();
 public void update();
}

package com.clj.demo3;

public class UserDaoImpl implements UserDao {

@Override
 public void save() {
   System.out.println("保存用户");
 }
 @Override
 public void update() {
   System.out.println("修改用户");
 }
}

   2)定义JDK * 工具类

此工具类是在执行持久层save方法时增加一些功能,在开发中做到在不更改源码情况下增强某方法


package com.clj.demo3;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
* 使用JDK的方式生成代理对象(演示AOP原理)
* @author Administrator
*
*/
public class MyProxyUtils {
 public static UserDao getProxy(final UserDao dao){
   //使用Proxy类生成代理对象
   UserDao proxy=(UserDao)Proxy.newProxyInstance(dao.getClass().getClassLoader() , dao.getClass().getInterfaces(),new InvocationHandler() {
     //只要代理对象一执行,invoke方法就会执行一次
     public Object invoke(Object proxy, Method method, Object[] args)
         throws Throwable {
       //proxy代表当前代理对象
       //method当前对象执行的方法
       //args封装的参数
       //让到类的save或者update方法正常执行下去
       if("save".equals(method.getName())){
         System.out.println("执行了保存");
         //开启事务
       }
       return method.invoke(dao, args);
     }
   });
   return proxy;
 }
}

 3)测试


package com.clj.demo3;

import org.junit.Test;

public class Demo1 {
 @Test
 public void run1(){
   //获取目标对象
   UserDao dao=new UserDaoImpl();
   dao.save();
   dao.update();
   System.out.println("===============");
   //使用工具类,获取到代理对象
   UserDao proxy=MyProxyUtils.getProxy(dao);
   //调用代理对象的方法
   proxy.save();
   proxy.update();

}
}

 2.实现CGLIB技术

1)定义持久层,此时没有接口


package com.clj.demo4;

public class BookDaoImpl {
 public void save(){
   System.out.println("保存图书");
 }
 public void update(){
   System.out.println("修改图书");
 }
}

  2)编写工具类


package com.clj.demo4;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
/**
* Cglib代理方式实现原理
* @author Administrator
*
*/
public class MyCglibUtils {
 /**
  * 使用CGLIB方式生成代理对象
  * @return
  */
 public static BookDaoImpl getProxy(){
   Enhancer enhancer=new Enhancer();
   //设置父类
   enhancer.setSuperclass(BookDaoImpl.class);
   //设置回调函数
   enhancer.setCallback(new MethodInterceptor() {

@Override
     public Object intercept(Object obj, Method method, Object[] objs,
         MethodProxy methodProxy) throws Throwable {
       if(method.getName().equals("save")){
       System.out.println("我保存了");
       System.out.println("代理对象执行了");
   }
       return methodProxy.invokeSuper(obj, objs);//是方法执行下去
     }
   });
   //生成代理对象
   BookDaoImpl proxy=(BookDaoImpl) enhancer.create();
   return proxy;
 }
}

  3)编写测试类


package com.clj.demo4;
import org.junit.Test;
public class Demo1 {
 @Test
 public void run1(){
   //目标对象
   BookDaoImpl dao=new BookDaoImpl();
   dao.save();
   dao.update();
   System.out.println("==========");
   BookDaoImpl proxy=MyCglibUtils.getProxy();
   proxy.save();
   proxy.update();
 }
}

 3、Spring基于AspectJ的AOP的开发(配置文件方式)

详解Spring框架入门

  1)部署环境,导入相对应的jar包

详解Spring框架入门

 2)创建配置文件,并引入AOP约束


<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"
     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">

 3)创建接口和实现类


package com.clj.demo5;

public interface CustomerDao {
 public void save();
 public void update();
}

package com.clj.demo5;
/**
* 采用配置文件的方式 诠释AOP
* @author Administrator
*
*/
public class CustomerDaoImpl implements CustomerDao {

@Override
 public void save() {
   //模拟异常
   //int a=10/0;
   System.out.println("保存客户了啊");
 }

@Override
 public void update() {
   // TODO Auto-generated method stub
   System.out.println("更新客户了啊");
 }

}

 4)定义切面类


package com.clj.demo5;

import org.aspectj.lang.ProceedingJoinPoint;

/**
* 切面类:切入点+通知
* @author Administrator
*
*/
public class MyAspectXml {
 /**
  * 通知(具体的增强)
  */
 public void log(){
   System.out.println("记录日志");
 }
 /**
  * 方法执行成功或者异常都会执行
  */
 public void after(){
   System.out.println("最终通知");
 }
 /**
  * 方法执行之后,执行后置通知,如果程序出现异常,后置通知不会执行
  */
 public void afterReturn(){
   System.out.println("后置通知");
 }
 /**
  * 方法执行之后,如果程序有异常,才会执行异常通知
  */
 public void afterThrowing(){
   System.out.println("异常通知");
 }
 /**
  * 环绕通知:方法执行之前和方法执行之后进行通知,
  * 默认情况下,目标对象的方法不能执行的,需要手动让目标对象执行
  */
 public void around(ProceedingJoinPoint joinPoint){
   System.out.println("环绕通知1");
   //手动让目标对象的方法执行
   try {
     joinPoint.proceed();
   } catch (Throwable e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
   }
   System.out.println("环绕通知2");
 }
}

 5)注入实现类和切面类


<?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" 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"> <!-- bean definitions here -->
 <!-- 配置客户的dao -->
 <bean id="customerDao" class="com.clj.demo5.CustomerDaoImpl"/>
 <!-- 编写切面类配置好 -->
 <bean id="myAspectXml" class="com.clj.demo5.MyAspectXml"/>
 <!-- 配置AOP -->
 <aop:config>
   <!-- 配置切面类:切入点+通知 (类型)-->
   <aop:aspect ref="myAspectXml">
     <!-- 配置前置通知,save方法执行之前,增强方法会执行 -->
     <!-- 切入点表达式:execution(public void com.clj.demo5.CustomerDaoImpl.save()) -->
     <!-- 切入点表达式:
       1.execution()固定的,必写
       2.public可以省略不写
       3.返回值   必写,严格根据切入点方法而定,否则增强方法不会执行,可以用*代替,表示任意的返回值
       4.包名   必写,可以用*代替(如:*..*(默认所有包); com.clj.*)
       5.类名   必写,可以部分用*(如*DaoImpl表示以'DaoImpl'结尾的持久层实现类),但不建议用*代替整个类名
       6.方法   必写,可以部分用*(如save*表示以'save'开头的方法),但不建议用*代替整个类名
       7.方法参数 根据实际方法而定,可以用'..'表示有0或者多个参数
      -->
     <!-- <aop:before method="log" pointcut="execution(public void com.clj.*.CustomerDaoImpl.save(..))"/> -->
     <aop:before method="log" pointcut="execution(* *..*.*DaoImpl.save*(..))"/>
   </aop:aspect>
 </aop:config>
</beans>

 6)测试


package com.clj.demo5;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo1 {
 @Resource(name="customerDao")
 private CustomerDao customerDao;
 @Test
 public void run(){
   customerDao.save();
   customerDao.update();
 }
}

扩展:切面类升级


<?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" 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"> <!-- bean definitions here -->
 <bean id="myAspectXml" class="com.clj.demo5.MyAspectXml"/>
 <aop:config>
   <aop:aspect ref="myAspectXml">
     <!-- 配置最终通知
     <aop:after method="after" pointcut="execution(* *..*.*DaoImpl.save*(..))"/>-->
     <!-- 配置后置通知
     <aop:after-returning method="afterReturn" pointcut="execution(* *..*.*DaoImpl.save*(..))"/>-->
     <!-- 配置异常通知
     <aop:after-throwing method="afterThrowing" pointcut="execution(* *..*.*DaoImpl.save*(..))"/>-->
     <aop:around method="around" pointcut="execution(* *..*.*DaoImpl.update*(..))"/>
   </aop:aspect>
 </aop:config>
</beans>

4、Spring框架AOP之注解方式

 1)创建接口和实现类


package com.clj.demo1;

public interface CustomerDao {
 public void save();
 public void update();
}


package com.clj.demo1;

public class CustomerDaoImpl implements CustomerDao{

@Override
 public void save() {
   // TODO Auto-generated method stub
   System.out.println("保存客户..");
 }

@Override
 public void update() {
   // TODO Auto-generated method stub
   System.out.println("更新客户");
 }

}

2)定义切面类


package com.clj.demo1;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

/**
* 注解方式的切面类
* @Aspect表示定义为切面类
*/
@Aspect
public class MyAspectAnno {
 //通知类型:@Before前置通知(切入点的表达式)
 @Before(value="execution(public *   com.clj.demo1.CustomerDaoImpl.save())")
 public void log(){
   System.out.println("记录日志。。");
 }
 //引入切入点
 @After(value="MyAspectAnno.fun()")
 public void after(){
   System.out.println("执行之后");
 }
 @Around(value="MyAspectAnno.fun()")
 public void around(ProceedingJoinPoint joinPoint){
   System.out.println("环绕通知1");
   try {
     //让目标对象执行
     joinPoint.proceed();
   } catch (Throwable e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
   }
   System.out.println("环绕通知2");
 }
 //自定义切入点
 @Pointcut(value="execution(public *   com.clj.demo1.CustomerDaoImpl.save())")
 public void fun(){

}
}

3)配置切面类和实现类,并开启自动代理


<?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:tx="http://www.springframework.org/schema/tx"
 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
 http://www.springframework.org/schema/tx
 http://www.springframework.org/schema/tx/spring-tx.xsd">
 <!-- 开启自动注解代理-->
 <aop:aspectj-autoproxy/>
 <!-- 配置目标对象 -->
 <bean id="customerDao" class="com.clj.demo1.CustomerDaoImpl"/>
 <!-- 配置切面类 -->
 <bean id="myAspectAnno" class="com.clj.demo1.MyAspectAnno"/>
</beans>

七、Spring之JDBC

spring提供了JDBC模板:JdbcTemplate类

1.快速搭建

 1)部署环境

这里在原有的jar包基础上,还要添加关乎jdbc的jar包,这里使用的是mysql驱动

详解Spring框架入门

 2)配置内置连接池,将连接数据库程序交给框架管理,并配置Jdbc模板类


<?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:tx="http://www.springframework.org/schema/tx"
 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
 http://www.springframework.org/schema/tx
 http://www.springframework.org/schema/tx/spring-tx.xsd">
 <!-- 先配置连接池(内置) -->
 <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
   <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
   <property name="url" value="jdbc:mysql://192.168.174.130:3306/SSH"/>
   <property name="username" value="root"/>
   <property name="password" value="root"/>
 </bean>
 <!-- 配置JDBC的模板类-->
 <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
   <property name="dataSource" ref="dataSource"/>
 </bean>
</beans>

 3)测试


package com.clj.demo2;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.dbcp.BasicDataSource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
* 测试JDBC的模板类,使用IOC的方式
* @author Administrator
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo2 {
 @Resource(name="jdbcTemplate")
 private JdbcTemplate jdbcTemplate;
 /**
  * 插入
  */
 @Test
 public void run1(){
   String sql="insert into t_account values(null,?,?)";
   jdbcTemplate.update(sql,"李钇林",10000);
 }
 /**
  * 更新
  */
 @Test
 public void run2(){
   String sql="update t_account set name=? where id=?";
   jdbcTemplate.update(sql,"李钇林",1);
 }
 /**
  * 删除
  */
 @Test
 public void run3(){
   String sql="delete from t_account where id=?";
   jdbcTemplate.update(sql,4);
 }
 /**
  * 测试查询,通过主键来查询一条记录
  */
 @Test
 public void run4(){
   String sql="select * from t_account where id=?";
   Account ac=jdbcTemplate.queryForObject(sql, new BeanMapper(),1);
   System.out.println(ac);
 }
 /**
  * 查询所有
  */
 @Test
 public void run5(){
   String sql="select * from t_account";
   List<Account> ac=jdbcTemplate.query(sql,new BeanMapper());
   System.out.println(ac);
 }
}
/**
* 定义内部类(手动封装数据(一行一行封装数据,用于查询所有)
* @author Administrator
*
*/
class BeanMapper implements RowMapper<Account>{

@Override
 public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
   Account ac=new Account();
   ac.setId(rs.getInt("id"));
   ac.setName(rs.getString("name"));
   ac.setMoney(rs.getDouble("money"));
   return ac;
 }

}

2、配置开源连接池

一般现在企业都是用一些主流的连接池,如c3p0和dbcp

首先配置dbcp

1)导入dbcp依赖jar包

详解Spring框架入门

2)编写配置文件


<!-- 配置DBCP开源连接池-->
 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
   <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
   <property name="url" value="jdbc:mysql://192.168.174.130:3306/SSH"/>
   <property name="username" value="root"/>
   <property name="password" value="root"/>
 </bean>

将模板类中引入的内置类datasource改为开源连接池的

3)编写测试类

配置c3p0

 1)导入c3p0依赖jar包

详解Spring框架入门

2)配置c3p0


<!-- 配置C3P0开源连接池 -->
 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
   <property name="driverClass" value="com.mysql.jdbc.Driver"/>
   <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"/>
   <property name="user" value="root"/>
   <property name="password" value="root"/>
 </bean>

将模板类中引入的内置类datasource改为开源连接池的

3)编写测试类

八、Spring之事务

1、什么是事务

数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。事务是数据库运行中的逻辑工作单位,由DBMS中的事务管理子系统负责事务的处理。

2、怎么解决事务安全性问题

读问题解决,设置数据库隔离级别;写问题解决可以使用 悲观锁和乐观锁的方式解决

3、快速开发

方式一:调用模板类,将模板注入持久层

1)编写相对应的持久层和也外层,这里省略接口


package com.clj.demo3;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{
 // 方式一:将jdbc模板类注入到配置文件中,直接在持久层写模板类
  private JdbcTemplate jdbcTemplate;
  public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
    this.jdbcTemplate = jdbcTemplate;
  }

public void outMoney(String out, double money) {
   String sql="update t_account set money=money-? where name=?";
   jdbcTemplate().update(sql,money,out);
 }

public void inMoney(String in, double money) {
   String sql="update t_account set money=money+? where name=?";
   jdbcTemplate().update(sql,money,in);
 }

}


package com.clj.demo4;

import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

public class AccountServiceImpl implements AccountService{
 //采用的是配置文件注入方式,必须提供set方法
 private AccountDao accountDao;
 public void setAccountDao(AccountDao accountDao) {
   this.accountDao = accountDao;
 }
 @Override
 public void pay(String out, String in, double money) {
   // TODO Auto-generated method stub
   accountDao.outMoney(out, money);
   int a=10/0;
   accountDao.inMoney(in, money);
 }
}

2)配置相对应的配置文件


<?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:tx="http://www.springframework.org/schema/tx"
 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
 http://www.springframework.org/schema/tx
 http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 配置C3P0开源连接池 -->
 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
   <property name="driverClass" value="com.mysql.jdbc.Driver"/>
   <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"/>
   <property name="user" value="root"/>
   <property name="password" value="root"/>
 </bean>
<!-- 配置JDBC的模板类 -->
 <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
   <property name="dataSource" ref="dataSource"/>
 </bean>
<!-- 配置业务层和持久层 -->
 <bean id="accountService" class="com.clj.demo3.AccountServiceImpl">
   <property name="accountDao" ref="accountDao"/>
 </bean>
<bean id="accountDao" class="com.clj.demo3.AccountDaoImpl">
   <!-- 注入模板类-->
   <property name="jdbcTemplate" ref="jdbcTemplate"/>  
   <property name="dataSource" ref="dataSource"/>
 </bean>
</beans>

3)测试类


package com.clj.demo3;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo1 {
 @Resource(name="accountService")
 private AccountService accountService;
 @Test
 public void Demo1(){
   //调用支付的方法
   accountService.pay("佳先森","李钇林",100);
 }
}

方式二:持久层继承JdbcDaoSupport接口,此接口封装了模板类jdbcTemplate

详解Spring框架入门

1)编写配置文件


<?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:tx="http://www.springframework.org/schema/tx"
 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
 http://www.springframework.org/schema/tx
 http://www.springframework.org/schema/tx/spring-tx.xsd">
 <!-- 配置C3P0开源连接池 -->
 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
   <property name="driverClass" value="com.mysql.jdbc.Driver"/>
   <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"/>
   <property name="user" value="root"/>
   <property name="password" value="root"/>
 </bean>
 <!-- 配置业务层和持久层 -->
 <bean id="accountService" class="com.clj.demo3.AccountServiceImpl">
   <property name="accountDao" ref="accountDao"/>
 </bean>
 <bean id="accountDao" class="com.clj.demo3.AccountDaoImpl">  
   <property name="dataSource" ref="dataSource"/>
 </bean>
</beans>

2)更改持久层


package com.clj.demo3;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{
 //方式一:将jdbc模板类注入到配置文件中,直接在持久层写模板类
//  private JdbcTemplate jdbcTemplate;
//  public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
//    this.jdbcTemplate = jdbcTemplate;
//  }

//方式二:持久层继承JdbcDaoSupport,它里面封转了模板类,配置文件持久层无需注入模板类,也不需要配置模板类
 public void outMoney(String out, double money) {
   //jdbcTemplate.update(psc);
   String sql="update t_account set money=money-? where name=?";
   this.getJdbcTemplate().update(sql,money,out);
 }

public void inMoney(String in, double money) {
   String sql="update t_account set money=money+? where name=?";
   this.getJdbcTemplate().update(sql,money,in);
 }

}

3)更改业务层


package com.clj.demo4;

import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

public class AccountServiceImpl implements AccountService{
 //采用的是配置文件注入方式,必须提供set方法
 private AccountDao accountDao;
 public void setAccountDao(AccountDao accountDao) {
   this.accountDao = accountDao;
 }
 @Override
 public void pay(String out, String in, double money) {
   // TODO Auto-generated method stub
   accountDao.outMoney(out, money);
   int a=10/0;
   accountDao.inMoney(in, money);
 }

}

4)测试类和上述一样

4、spring事务管理

Spring为了简化事务管理的代码:提供了模板类 TransactionTemplate,手动编程的方式来管理事务,只需要使用该模板类即可!!

九、Spring框架的事务管理之编程式的事务管理

1、手动编程方式事务(了解原理)

1)快速部署,搭建配置文件,配置事务管理和事务管理模板,并在持久层注入事务管理模板

配置事务管理器


<!-- 配置平台事务管理器 -->
 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   <property name="dataSource" ref="dataSource"/>
 </bean>

配置事务管理模板


<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
   <property name="transactionManager" ref="transactionManager"/>
</bean>

将管理模板注入业务层


<bean id="accountService" class="com.clj.demo3.AccountServiceImpl">
   <property name="accountDao" ref="accountDao"/>
   <property name="transactionTemplate" ref="transactionTemplate"/>
</bean>

全部代码:


<?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:tx="http://www.springframework.org/schema/tx"
 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
 http://www.springframework.org/schema/tx
 http://www.springframework.org/schema/tx/spring-tx.xsd">

<!-- 配置C3P0开源连接池 -->
 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
   <property name="driverClass" value="com.mysql.jdbc.Driver"/>
   <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"/>
   <property name="user" value="root"/>
   <property name="password" value="root"/>
 </bean>
 <!-- 配置业务层和持久层 -->
 <bean id="accountService" class="com.clj.demo3.AccountServiceImpl">
   <property name="accountDao" ref="accountDao"/>
   <property name="transactionTemplate" ref="transactionTemplate"/>
 </bean>
 <bean id="accountDao" class="com.clj.demo3.AccountDaoImpl">  
   <property name="dataSource" ref="dataSource"/>
 </bean>
 <!-- 配置平台事务管理器 -->
 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   <property name="dataSource" ref="dataSource"/>
 </bean>
 <!-- 手动编码方式,提供了模板类,使用该类管理事务比较简单-->
 <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
   <property name="transactionManager" ref="transactionManager"/>
 </bean>
</beans>

2)在业务层使用模板事务管理


package com.clj.demo3;

import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

public class AccountServiceImpl implements AccountService{
 //采用的是配置文件注入方式,必须提供set方法
 private AccountDao accountDao;
 //注入事务模板类
 private TransactionTemplate transactionTemplate;
 public void setAccountDao(AccountDao accountDao) {
   this.accountDao = accountDao;
 }

public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
   this.transactionTemplate = transactionTemplate;
 }

/**
  * 转账的方法
  */
 public void pay(final String out,final String in, final double money) {
   transactionTemplate.execute(new TransactionCallbackWithoutResult() {
     //事务的执行,如果没有问题,提交,如果楚翔异常,回滚
     protected void doInTransactionWithoutResult(TransactionStatus arg0) {
       // TODO Auto-generated method stub
       accountDao.outMoney(out, money);
       int a=10/0;
       accountDao.inMoney(in, money);
     }
   });
 }

}

3)测试类和上一致


package com.clj.demo4;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext2.xml")
public class Demo2 {
 @Resource(name="accountService")
 private AccountService accountService;
 @Test
 public void Demo1(){
   //调用支付的方法
   accountService.pay("佳先森","李钇林",100);
 }
}

十、Spring框架的事务管理之声明式事务管理,即通过配置文件来完成事务管理(AOP思想)

申明式事务有两种方式:基于AspectJ的XML方式;基于AspectJ的注解方式

1、XML方式

1)配置配置文件

需要配置平台事务管理


<!-- 配置C3P0开源连接池 -->
 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
   <property name="driverClass" value="com.mysql.jdbc.Driver"/>
   <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"/>
   <property name="user" value="root"/>
   <property name="password" value="root"/>
 </bean>
 <!-- 配置平台事务管理器 -->
 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   <property name="dataSource" ref="dataSource"/>
 </bean>

配置事务增强


<tx:advice id="myAdvice" transaction-manager="transactionManager">
   <tx:attributes>
     <!-- 给方法设置数据库属性(隔离级别,传播行为) -->
     <!--propagation事务隔离级别:一般采用默认形式:tx:method可以设置多个 -->
     <tx:method name="pay" propagation="REQUIRED"/>
   </tx:attributes>
 </tx:advice>

aop切面类


<aop:config>
   <!-- aop:advisor,是spring框架提供的通知-->
   <aop:advisor advice-ref="myAdvice" pointcut="execution(public * com.clj.demo4.AccountServiceImpl.pay(..))"/>
 </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:aop="http://www.springframework.org/schema/aop"
 xmlns:tx="http://www.springframework.org/schema/tx"
 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
 http://www.springframework.org/schema/tx
 http://www.springframework.org/schema/tx/spring-tx.xsd">
 <!-- 配置C3P0开源连接池 -->
 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
   <property name="driverClass" value="com.mysql.jdbc.Driver"/>
   <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"/>
   <property name="user" value="root"/>
   <property name="password" value="root"/>
 </bean>
 <!-- 配置平台事务管理器 -->
 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   <property name="dataSource" ref="dataSource"/>
 </bean>
 <!-- 申明式事务(采用XML文件的方式) -->
 <!-- 先配置通知 -->
 <tx:advice id="myAdvice" transaction-manager="transactionManager">
   <tx:attributes>
     <!-- 给方法设置数据库属性(隔离级别,传播行为) -->
     <!--propagation事务隔离级别:一般采用默认形式:tx:method可以设置多个 -->
     <tx:method name="pay" propagation="REQUIRED"/>
   </tx:attributes>
 </tx:advice>
 <!-- 配置AOP:如果是自己编写的AOP,使用aop:aspect配置,使用的是Spring框架提供的通知 -->
 <aop:config>
   <!-- aop:advisor,是spring框架提供的通知-->
   <aop:advisor advice-ref="myAdvice" pointcut="execution(public * com.clj.demo4.AccountServiceImpl.pay(..))"/>
 </aop:config>

<!-- 配置业务层和持久层 -->
 <bean id="accountService" class="com.clj.demo4.AccountServiceImpl">
   <property name="accountDao" ref="accountDao"/>
 </bean>
 <bean id="accountDao" class="com.clj.demo4.AccountDaoImpl">
   <property name="dataSource" ref="dataSource"/>
 </bean>
</beans>

2)编写持久层和业务层(省略接口)


package com.clj.demo5;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{
 //方式一:将jdbc模板类注入到配置文件中,直接在持久层写模板类
//  private JdbcTemplate jdbcTemplate;
//  public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
//    this.jdbcTemplate = jdbcTemplate;
//  }

//方式二:持久层继承JdbcDaoSupport,它里面封转了模板类,配置文件持久层无需注入模板类,也不需要配置模板类
 public void outMoney(String out, double money) {
   //jdbcTemplate.update(psc);
   String sql="update t_account set money=money-? where name=?";
   this.getJdbcTemplate().update(sql,money,out);
 }

public void inMoney(String in, double money) {
   String sql="update t_account set money=money+? where name=?";
   this.getJdbcTemplate().update(sql,money,in);
 }

}


package com.clj.demo5;

import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;public class AccountServiceImpl implements AccountService{
 //采用的是配置文件注入方式,必须提供set方法
 private AccountDao accountDao;
 public void setAccountDao(AccountDao accountDao) {
   this.accountDao = accountDao;
 }
 @Override
 public void pay(String out, String in, double money) {
   // TODO Auto-generated method stub
   accountDao.outMoney(out, money);
   int a=10/0;
   accountDao.inMoney(in, money);
 }

}

3)测试类


package com.clj.demo4;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext2.xml")
public class Demo2 {
 @Resource(name="accountService")
 private AccountService accountService;
 @Test
 public void Demo1(){
   //调用支付的方法
   accountService.pay("佳先森","李钇林",100);
 }
}

2、注解方式

1)配置配置文件

配置事务管理


<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
   <property name="driverClass" value="com.mysql.jdbc.Driver"/>
   <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"/>
   <property name="user" value="root"/>
   <property name="password" value="root"/>
 </bean>
 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   <property name="dataSource" ref="dataSource"/>
 </bean>

开启注释事务


 <!-- 开启事务的注解 -->
 <tx:annotation-driven transaction-manager="transactionManager"/>

全部代码


<?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:tx="http://www.springframework.org/schema/tx"
 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
 http://www.springframework.org/schema/tx
 http://www.springframework.org/schema/tx/spring-tx.xsd">
 <!-- 配置C3P0开源连接池 -->
 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
   <property name="driverClass" value="com.mysql.jdbc.Driver"/>
   <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"/>
   <property name="user" value="root"/>
   <property name="password" value="root"/>
 </bean>
 <!-- 配置平台事务管理器 -->
 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   <property name="dataSource" ref="dataSource"/>
 </bean>
 <!-- 开启事务的注解 -->
 <tx:annotation-driven transaction-manager="transactionManager"/>

<!-- 配置业务层和持久层 -->
 <bean id="accountService" class="com.clj.demo5.AccountServiceImpl">
   <property name="accountDao" ref="accountDao"/>
 </bean>
 <bean id="accountDao" class="com.clj.demo5.AccountDaoImpl">
   <property name="dataSource" ref="dataSource"/>
 </bean>
</beans>

2)业务层增加@Transactional


package com.clj.demo5;

import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
//在当前类加此注解表示当前类所有的全部都有事务
@Transactional
public class AccountServiceImpl implements AccountService{
 //采用的是配置文件注入方式,必须提供set方法
 private AccountDao accountDao;
 public void setAccountDao(AccountDao accountDao) {
   this.accountDao = accountDao;
 }
 @Override
 public void pay(String out, String in, double money) {
   // TODO Auto-generated method stub
   accountDao.outMoney(out, money);
   int a=10/0;
   accountDao.inMoney(in, money);
 }

}

3)持久层不变


package com.clj.demo5;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{
 //方式一:将jdbc模板类注入到配置文件中,直接在持久层写模板类
//  private JdbcTemplate jdbcTemplate;
//  public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
//    this.jdbcTemplate = jdbcTemplate;
//  }

//方式二:持久层继承JdbcDaoSupport,它里面封转了模板类,配置文件持久层无需注入模板类,也不需要配置模板类
 public void outMoney(String out, double money) {
   //jdbcTemplate.update(psc);
   String sql="update t_account set money=money-? where name=?";
   this.getJdbcTemplate().update(sql,money,out);
 }

public void inMoney(String in, double money) {
   String sql="update t_account set money=money+? where name=?";
   this.getJdbcTemplate().update(sql,money,in);
 }

}

4)测试类


package com.clj.demo5;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext3.xml")
public class Demo3 {
@Resource(name="accountService")
private AccountService accountService;
@Test
public void Demo1(){
 //调用支付的方法
 accountService.pay("佳先森","李钇林",100);
}
}

来源:http://www.cnblogs.com/cailijia52o/p/8699845.html

标签:Spring,框架
0
投稿

猜你喜欢

  • c#获取两个特定字符之间的内容并输出的方法

    2021-12-02 19:47:11
  • Java反转链表测试过程介绍

    2022-10-02 20:10:03
  • SpringBoot Jpa分页查询配置方式解析

    2023-03-02 10:04:02
  • java中单例模式讲解

    2022-05-22 14:24:07
  • Android简单实现菜单拖拽排序的功能

    2023-03-10 22:32:31
  • Java利用数组随机抽取幸运观众如何实现

    2022-03-20 11:51:02
  • Android利用Canvas标点画线并加入位移动画(2)

    2022-04-09 07:57:02
  • 使用IDEA搭建ssm框架的详细图文教程

    2021-12-04 10:37:20
  • C# Double转化为String时的保留位数及格式方式

    2021-09-08 13:12:00
  • 详解Java如何进行Base64的编码(Encode)与解码(Decode)

    2023-01-31 18:53:34
  • window下安装和配置maven环境

    2021-06-13 14:32:16
  • Spring Boot 整合mybatis 与 swagger2

    2022-05-01 06:32:17
  • C# web.config之<customErrors>节点说明案例详解

    2023-07-06 20:20:15
  • Android自定义UI手势密码终结版

    2021-07-29 15:40:17
  • Springboot 整合shiro实现权限控制的方法

    2021-09-21 20:15:47
  • Toolbar制作菜单条过程详解

    2022-11-29 04:13:59
  • 基于Java中两种jersey文件上传方式

    2022-03-02 10:47:29
  • Android 自定义TextView实现文本内容自动调整字体大小

    2023-11-07 11:47:40
  • SpringBoot如何自动生成API文档详解

    2023-05-24 13:44:37
  • Android PullToRefreshLayout下拉刷新控件的终结者

    2021-06-22 02:15:00
  • asp之家 软件编程 m.aspxhome.com