蒋振飞的博客 - Java进阶03:Spring教程   
正在加载蒋振飞的博客...
V3.0
蒋振飞的博客

Java进阶03:Spring教程

发布时间: 2019年01月19日 发布人: 蒋振飞 热度: 332 ℃ 评论数: 0

一、Spring的概述

1.什么是Spring?

    Spring是一个分层的JavaSE/EE的一站式轻量级开源框架。

2.Spring的优点

    1) 方便解耦,简化开发

        使用Spring,用户不需要再为单实例模式类,属性文件解析等类似很底层的需要编写代码,可以更专注于上层的应用。

    2) AOP编程的支持

        方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付。

    3) 声明式事务的支持

        通过声明式灵活地进行事务的管理,提高开发效率和质量。

    4) 方便程序的测试

        可以使用非容器依赖的方式进行几乎所有的测试工作。

    5) 方便集成各种优秀的框架

        可以降低各种框架的使用难度。

    6) 降低JavaEE API的使用难度

        Spring对很多难用的JavaEE API(如JDBC,JavaMail,远程调用等)提供了一个薄薄的封装层。

3.什么是IOC?

    IOC英文全称是Inversion of Control,有控制反转的意思,也就是将对象的创建权反转给Spring。

4 .Spring的入门使用

    1) Spring的官网地址

        http://spring.io

    2) Spring开发包

docs        :Spring的开发规范和API
libs        :Spring的开发的jar和源码
schema      :Spring的配置文件的约束

    3) 创建接口和测试类

// 用户管理DAO层接口
public interface UserDAO {
    public void save();
}
 
// 用户管理DAO层实现类
public class UserDAOImpl implements UserDAO {
    private String name;
 
    public void setName(String name) {
        this.name = name;
    }
 
    @Override
    public void save() {
        System.out.println("UserDAOImpl执行了..."+name);
    }
}

        如果底层的实现切换了,需要修改源代码,要想实现不修改程序源代码就可以对程序进行扩展,需要将类交给Spring管理。

    4) 将实现类交给Spring管理

        在spring的解压路径下spring-framework-4.2.4.RELEASE\docs\spring-framework-reference\html\xsd-configuration.html。

<?xml version="1.0" encoding="UTF-8"?>
<beans 
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd">
 
    <!-- Spring的入门的配置==================== -->
    <bean name="userDAO" class="com.jzfblog.spring.demo1.UserDAOImpl">
        <!--依赖注入-->
        <property name="name" value="李东"/>
    </bean>
</beans>

        5) 编写测试类

// Spring的方式的调用
public void demo2(){
    // 创建Spring的工厂
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserDAO userDAO = (UserDAO) applicationContext.getBean("userDAO");
    userDAO.save();
}

二、Spring的工厂类

1.Spring工厂类的结构图

    beanfactory.png

    ApplicationContext继承BeanFactory

2.BeanFactory:老版本的工厂类 

   BeanFactory:调用getBean的时候,才会生成类的实例。

3.ApplicationContext:新版本的工厂类

ApplicationContext:加载配置文件的时候,就会将Spring管理的类都实例化。
ApplicationContext有两个实现类
    ClassPathXmlApplicationContext   :加载类路径下的配置文件
    FileSystemXmlApplicationContext  :加载文件系统下的配置文件

4.加载磁盘上的配置文件

public void demo3(){
    ApplicationContext applicationContext = new FileSystemXmlApplicationContext("C:\\applicationContext.xml");
    UserDAO userDAO = (UserDAO) applicationContext.getBean("userDAO");
    userDAO.save();
}

三、Spring的配置

1.Bean的相关的配置

    1) 标签的id和name的配置

id      :使用了约束中的唯一约束。里面不能出现特殊字符的。
name     :没有使用约束中的唯一约束(理论上可以出现重复的,但是实际开发不能出现的),里面可以出现特殊字符。

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

init-method      :Bean被初始化的时候执行的方法。
destroy-method    :Bean被销毁的时候执行的方法(Bean是单例创建,工厂关闭)。

        ①xml代码

<!-- Spring的sBean的生命周期的配置=========== -->
<bean id="customerDAO" class="com.jzfblog.spring.demo2.CustomerDAOImpl" scope="prototype" init-method="setup" destroy-method="destroy"/>

        ②dao层代码

public class CustomerDAOImpl implements CustomerDAO {
 
    public void setup(){
        System.out.println("CustomerDAOImpl初始化...");
    }
 
    @Override
    public void save() {
        System.out.println("CustomerDAOImpl执行了...");
    }
 
    public void destroy(){
        System.out.println("CustomerDAOImpl销毁了...");
    }
 
}

        ③web层代码

public void demo1(){
    ClassPathXmlApplicationContext applicationContext= new ClassPathXmlApplicationContext("applicationContext.xml");
    CustomerDAO customerDAO = (CustomerDAO) applicationContext.getBean("customerDAO");
    customerDAO.save();
    // 关闭工厂
    applicationContext.close();
}

    3) Bean的作用范围的配置(重点)

scope             :Bean的作用范围
    singleton      :默认的,Spring会采用单例模式创建这个对象。
    prototype      :多例模式。(Struts2和Spring整合一定会用到)
    request        :应用在web项目中,Spring创建这个类以后,将这个类存入到request范围中。
    session        :应用在web项目中,Spring创建这个类以后,将这个类存入到session范围中。
    globalsession     :应用在web项目中,必须在porlet环境下使用。但是如果没有这种环境,相对于session。

2.Spring的Bean管理(XML方式)

    1) Spring的Bean的实例化方式(了解)

        ①无参构造方法的方式(默认)

// 无参数构造方式
public class Bean1 {
 
    public Bean1() {
        super();
        System.out.println("Bean1无参构造方法执行了...");
    }
}

<!-- 无参数构造方法 -->
<bean id="bean1" class="com.jzfblog.spring.demo3.Bean1"></bean>

        ②静态工厂实例化的方式

// 编写Bean2的静态工厂
public class Bean2Factory {
 
    public static Bean2 createBean2(){
        System.out.println("Bean2Factory中方法执行了...");
        return new Bean2();
    }
}

// 编写配置
<!-- 静态工厂实例化 -->
<bean id="bean2" class="com.jzfblog.spring.demo3.Bean2Factory" factory-method="createBean2"/>

        ③实例工厂实例化的方式

// Bean3的实例工厂
public class Bean3Factory {
 
    public Bean3 createBean3(){
        System.out.println("Bean3的实例工厂执行了...");
        return new Bean3();
    }
}

// 编写配置
<!-- 实例工厂实例化 -->
<bean id="bean3Factory" class="com.jzfblog.spring.demo3.Bean3Factory"></bean> 
<bean id="bean3" factory-bean="bean3Factory" factory-method="createBean3"></bean>

    2) 普通的属性注入

        ①构造方法的方式的属性注入

<!-- 构造方法的方式 -->
<bean id="car" class="com.jzfblog.spring.demo4.Car">
    <constructor-arg name="name" value="宝马"/>
    <constructor-arg name="price" value="800000"/>
</bean>

        ②Set方法的方式的属性注入

<!-- set方法属性的方式 -->
<bean id="car2" class="com.jzfblog.spring.demo4.Car2">
    <property name="name" value="奔驰"/>
    <property name="price" value="1000000"/>
</bean>

<!-- set方法注入对象类型的属性 -->
<bean id="employee" class="com.jzfblog.spring.demo4.Employee">
    value:设置普通类型的值,ref:设置其他的类的id或name
    <property name="name" value="涛哥"/>
    <property name="car2" ref="car2"/>
</bean>

    3) P名称空间的属性注入(Spring2.5以后)

        ①P名称空间的引入

xmlns:p="http://www.springframework.org/schema/p"

        ②写法

普通属性    p:属性名=”值”
对象属性    p:属性名-ref=”值”

        ③使用p名称空间

<!-- 改为p名称空间的方式 -->
<bean id="car2" class="com.jzfblog.spring.demo4.Car2" p:name="奇瑞QQ" p:price="30000"></bean>
<bean id="employee" class="com.jzfblog.spring.demo4.Employee" p:name="王东" p:car2-ref="car2"></bean>

    4) SpEL的属性注入(Spring3.0以后)

        SpEL:Spring Expression Language,Spring的表达式语言。

语法:#{SpEL}
<!-- SpEL的属性注入 -->
<bean id="carInfo" class="com.jzfblog.spring.demo4.CarInfo">
</bean>
 
<bean id="car2" class="com.jzfblog.spring.demo4.Car2">
    <property name="name" value="#{carInfo.name}"></property>
    <property name="price" value="#{carInfo.calculatorPrice()}"></property>
</bean>
 
<bean id="employee" class="com.jzfblog.spring.demo4.Employee">
    <property name="name" value="#{'赵洪'}"></property>
    <property name="car2" value="#{car2}"></property>
</bean>

    5) 集合类型的属性注入

<bean id="collectionBean" class="com.jzfblog.spring.demo5.CollectionBean">
    <!-- 数组类型 -->
    <property name="arrs">
        <list>
            <value>1</value>
            <value>2</value>
            <value>3</value>
        </list>
    </property>
 
    <!-- 注入list集合 -->
    <property name="list">
        <list>
            <value>1</value>
            <value>2</value>
            <value>3</value>
        </list>
    </property>
 
    <!-- 注入set集合 -->
    <property name="set">
        <set>
            <value>1</value>
            <value>2</value>
            <value>3</value>
        </set>
    </property>
 
    <!-- 注入Map集合 -->
    <property name="map">
        <map>
            <entry key="a" value="1"/>
            <entry key="b" value="2"/>
            <entry key="c" value="3"/>
        </map>
    </property>
</bean>

四、Spring的分模块开发的配置

1.在加载多个配置文件

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml", applicationContext2.xml);

2.在一个配置文件中引入多个配置文件

<import resource="applicationContext2.xml"/>

五、Spring的IOC注解开发

1.IOC注解开发步骤

    1) 引入jar包

        在Spring4的版本中,除了引入基本的开发包以外,还需要引入AOP的包。

    2) 引入Spring的配置文件

        在src下创建applicationContext.xml,引入context约束。

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

    3) 配置注解扫描

<!-- Spring 的注解开发:组件扫描(类上注解: 可以直接使用属性注入的注解) -->
<context:component-scan base-package="com.jzfblog.spring.demo1"/>

    4) 在相关的类上添加注解

@Component(value="userDao") // 相当于:<bean id="userDao" class="com.jzfblog.spring.demo1.UserDaoImpl" />
public class UserDaoImpl implements UserDao {
 
    @Override
    public void sayHello() {
        System.out.println("Hello Spring Annotation...");
    }
}

    5) 编写测试类

@Test
public void demo1() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
    "applicationContext.xml");
    UserDao userDao = (UserDao) applicationContext.getBean("userDao");
    userDao.sayHello();
}

    6) 注解方式设置属性值

        ①属性如果有set方法,需要将属性注入的注解添加到set方法

private String name;
@value("张三")
public void setName(String name){
 
    this.name = name;
}

        ②属性如果没有set方法,需要将属性注入的注解添加到属性上

@value("张三")
private String name;
public void setName(String name){
 
    this.name = name;
}

2.IOC注解的详解

    1) @Component:组件

        修饰一个类,将这个类交给Spring管理。

三个衍生注解(功能类似),修饰类
@Controller  :web层
@Service    :service层
@Repository  :dao层

    2) 属性注入的注解

        ①普通属性

@value  :设置普通属性值

        ②对象属性

@Autowired  :按照类型完成属性注入
@Qualifier  :与Autowired配合使用,完成按照名称属性注入
@Resource   :完成对象属性注入,用于替代上面两个

    3) Bean的其他注解

        ①生命周期相关的注解

@PostConstruct    :初始化方法
@PreDestory      :销毁方法

        ②Bean作用访问注解

@Scope         :作用范围
    singleton   :默认单例
    prototype   :多例
    request
    session
    globalsession

3.XML与注解

    1) 使用场景

        XML:可以适用任何场景。
        注解:有些地方用不了,比如不是自己提供的类。

    2) XML和注解开发整合开发

        XML管理类,注解完成属性注入。

<!-- 在没有扫描的情况下,使用属性注入的注解:@Resource、@Autowired、@Value、@Qulifier -->
<context:annotation-config/>

六、Spring的AOP的XML开发

1.什么是AOP

    AOP是Aspect Oriented Programming的缩写,表示面向切面编程。

2.Spring底层的AOP实现原理

    JDK 的动态代理:针对实现了接口的类产生代理。

public class MyJDKProxy implements InvocationHandler {
    private UserDao userDao;
    public MyJDKProxy(UserDao userDao) {
        this.userDao = userDao;
    }
    // 编写工具方法:生成代理:
    public UserDao createProxy(){
        UserDao userDaoProxy = (UserDao)
        Proxy.newProxyInstance(userDao.getClass().getClassLoader(),
        userDao.getClass().getInterfaces(), this);
        return userDaoProxy;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    {
        if("save".equals(method.getName())){
            System.out.println("权限校验...");
        }
        return method.invoke(userDao, args);
    }
}

    Cglib 的动态代理:针对没有实现接口的类产生代理,属于第三方开源代码生成类库,动态添加类的属性和方法。

public class MyCglibProxy implements MethodInterceptor{
    private CustomerDao customerDao;
    public MyCglibProxy(CustomerDao customerDao){
        this.customerDao = customerDao;
    }
    // 生成代理的方法:
    public CustomerDao createProxy(){
        // 创建 Cglib 的核心类:
        Enhancer enhancer = new Enhancer();
        // 设置父类:
        enhancer.setSuperclass(CustomerDao.class);
        // 设置回调:
        enhancer.setCallback(this);
        // 生成代理:
        CustomerDao customerDaoProxy = (CustomerDao) enhancer.create();
        return customerDaoProxy;
    }
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy
    methodProxy) throws Throwable {
        if("delete".equals(method.getName())){
            Object obj = methodProxy.invokeSuper(proxy, args);
            System.out.println("日志记录...");
            return obj;
        }
        return methodProxy.invokeSuper(proxy, args);
    }
}

3.Spring基于AspectJ的AOP开发

    AOP 的开发中的相关术语

Joinpoint(连接点)     :所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点。
Pointcut(切入点)      :所谓切入点是指我们要对哪些Joinpoint进行拦截的定义。
Advice(通知/增强)     :所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)。
Introduction(引介)    :引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方法或 Field。
Target(目标对象)      :代理的目标对象。
Weaving(织入)         :是指把增强应用到目标对象来创建新的代理对象的过程。
spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装在期织入。
Proxy(代理)         :一个类被 AOP 织入增强后,就产生一个结果代理类。
Aspect(切面)          : 是切入点和通知(引介)的结合。

AOP.png

4.Spring的AOP的入门(AspectJ的XML的方式)

    1) 引入jar包

* spring 的传统 AOP 的开发的包
spring-aop-4.2.4.RELEASE.jar
com.springsource.org.aopalliance-1.0.0.jar
* aspectJ 的开发包
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aspects-4.2.4.RELEASE.jar

    2) 引入Spring的配置文件

<?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 -->
 
</beans>

    3) 编写目标类

public class OrderDaoImpl implements OrderDao {
    @Override
    public void save() {
        System.out.println("保存订单...");
    }
    @Override
    public void update() {
        System.out.println("修改订单...");
    }
    @Override
    public void delete() {
        System.out.println("删除订单...");
    }
    @Override
    public void find() {
        System.out.println("查询订单...");
    }
}

    4) 目标类的配置

<!-- 目标类================ -->
<bean id="orderDao" class="com.jzfblog.spring.demo3.OrderDaoImpl">
</bean>

    5) 编写测试类(整合Junit单元测试)

        引入 spring-test.jar

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDemo3 {
 
    @Resource(name="orderDao")
    private OrderDao orderDao;
 
    @Test
    public void demo1(){
        orderDao.save();
        orderDao.update();
        orderDao.delete();
        orderDao.find();
    }
}

    6) 通知类型

前置通知(before) :在目标方法执行之前执行,获得切入点信息。
后置通知(after-returning) :在目标方法执行之后执行,获得方法的返回值。
环绕通知(around) :在目标方法执行前和执行后执行,可阻止目标方法的执行。
异常抛出通知(after-throwing):在目标方法执行出现异常的时候执行。
最终通知(after) :无论目标方法是否出现异常,最终通知都会执行。

    7) 切入点表达式

execution(表达式)
表达式:
[方法访问修饰符] 方法返回值 包名.类名.方法名(方法的参数)
public * com.jzfblog.spring.dao.*.*(..)
* com.jzfblog.spring.dao.*.*(..)
* com.jzfblog.spring.dao.UserDao+.*(..)
* com.jzfblog.spring.dao..*.*(..)

    8) 编写一个切面类

public class MyAspect {
    // 前置增强
    public void before(){
        System.out.println("前置增强===========");
    }
}

    9) 配置完成增强

<!-- 配置切面类 -->
<bean id="myAspect" class="com.jzfblog.spring.demo3.MyAspect"></bean>
 
<!-- 进行 aop 的配置 -->
<aop:config>
    <!-- 配置切入点表达式:哪些类的哪些方法需要进行增强 -->
    <!-- *代表任意返回值,..代表任意参数 -->
    <aop:pointcut expression="execution(* com.jzfblog.spring.demo3.OrderDao.save(..))" id="pointcut1"/>
    <!-- 配置切面 -->
    <aop:aspect ref="myAspect">
        <aop:before method="before" pointcut-ref="pointcut1"/>
    </aop:aspect>
</aop:config>

5.Spring的AOP的入门(AspectJ的注解开发)

    1) 引入jar包

com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.apache.commons.logging-1.1.1.jar
com.springsource.org.apache.log4j-1.2.15.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aop-4.2.4.RELEASE.jar
spring-aspects-4.2.4.RELEASE.jar
spring-beans-4.2.4.RELEASE.jar
spring-context-4.2.4.RELEASE.jar
spring-core-4.2.4.RELEASE.jar
spring-expression-4.2.4.RELEASE.jar

    2) 引入配置文件

    3) 编写目标类并配置

<!-- 配置目标类================ -->
<bean id="orderDao" class="com.jzfblog.spring.demo1.OrderDaoImpl">
 
</bean>

    4) 编写切面类并配置

public class MyAspectAnno{
 
    public void before(){
        System.out.println("前置增强=======")
    }
}
 
<!--配置切面类-->
<bean id="myAspect" class="com.jzfblog.spring.demo1.MyAspectAnno">
</bean>

    5) 使用注解的AOP对象目标类进行增强

<!-- 在配置文件中开启注解的AOP的开发 -->
<aop:aspectj-autoproxy/>

    在切面类上使用注解

@Aspect
public class MyAspectAnno {
 
    @Before(value="execution(* com.jzfblog.spring.demo1.OrderDaoImpl.before(..))")
    public void before(){
        System.out.println("前置增强....");
    }
}
-------------------------------------------
@Aspect
public class MyAspectAnno {
 
    @Before(value="MyAspectAnno.pointcut1()")
    public void before(){
        System.out.println("前置增强....");
    }
 
    // 切入点注解
    @Pointcut(value="execution(* com.jzfblog.spring.demo1.OrderDao.save(..))")
    private void pointcut1(){}
}

    6) 编写测试类

        引入 spring-test.jar。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDemo1 {
    @Resource(name="orderDao")
    private OrderDao orderDao;
 
    @Test
    public void demo1(){
        orderDao.save();
    }
}

七、Spring的JDBC模板使用

1.Spring的JDBC的模板

    Spring是EE开发的一站式的框架,有EE开发的每层的解决方案。Spring对持久层也提供了解决方案:ORM模块和JDBC的模板。

Spring提供了很多的模板用于简化开发:
JDBC            :org.springframework.jdbc.core.JdbcTemplate
Hibernate5.0    :org.springframework.orm.hibernate5.HibernateTemplate
IBatis(MyBatis) :org.springwork.orm.ibatis.SqlMapClientTemplate
JPA             :org.springframework.orm.jpa.JpaTemplate

2.JDBC模板使用入门

    1) 引入jar包

引入基本开发包:
com.springsource.org.apache.commons.logging-1.1.1.jar
com.springsource.org.apache.log4j-1.2.15.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-beans-4.2.4.RELEASE.jar
spring-context-4.2.4.RELEASE.jar
spring-core-4.2.4.RELEASE.jar
spring-expression-4.2.4.RELEASE.jar
 
数据库驱动:
mysql-connector-java.jar
 
Spring的JDBC模板的jar包:
spring-jdbc.RELEASE.jar
spring-tx.RELEASE.jar

    2) 创建数据库和表

    3) 使用JDBC的模板:保存数据

public class JdbcDemo1 {
 
    @Test
    // jdbc模板的使用类似于Dbutils.
    public void demo1(){
        // 创建连接池:
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql:///spring_jdbc");
        dataSource.setUsername("root");
        dataSource.setPassword("abc");
        // 创建jdbc模板
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        jdbcTemplate.update("insert into account values (null,?,?)", "java",10000d);
    }
}

    4) 将连接池和模板交给Spring管理

        ①引入Spring的配置文件

<!-- 配置Spring的内置的连接池 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql:///spring4_jdbc"/>
    <property name="username" value="root"/>
    <property name="password" value="abc"/>
</bean>
 
<!-- 配置Spring的JDBC的模板========================= -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource" />
</bean>

        ②使用Jdbc的模板

            引入spring_aop的jar包,否则将无法正常执行。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class JdbcDemo2 {
    @Resource(name="jdbcTemplate")
    private JdbcTemplate jdbcTemplate;
 
    @Test
    // 保存操作
    public void demo1(){
        jdbcTemplate.update("insert into account values (null,?,?)", "python",10000d);
    }
}

    5) 使用开源的数据库连接池

        ①DBCP的使用

            引入jar包

com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar
com.springsource.org.apache.commons.pool-1.5.3.jar

            配置DBCP连接池

<!-- 配置DBCP连接池=============================== -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql:///spring4_jdbc"/>
    <property name="username" value="root"/>
    <property name="password" value="abc"/>
</bean>
 
<!-- 配置Spring的JDBC的模板========================= -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource" />
</bean>

        ②C3P0的使用

            引入c3p0连接池jar包

com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar

            配置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:///spring_jdbc"/>
    <property name="user" value="root"/>
    <property name="password" value="abc"/>
</bean>
 
<!-- 配置Spring的JDBC的模板========================= -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource" />
</bean>

    6) 抽取配置到属性文件

        ①定义一个属性文件(jdbc.properties)

jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///spring4_jdbc
jdbc.username=root
jdbc.password=abc

        ②在Spring的配置文件中引入属性文件

<!-- 第一种方式通过一个bean标签引入的(很少) -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location" value="classpath:jdbc.properties"/>
</bean>
 
<!-- 第二种方式通过context标签引入的 -->
<context:property-placeholder location="classpath:jdbc.properties"/>

        ③引入属性文件的值

<!-- 配置C3P0连接池=============================== -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${jdbc.driverClass}"/>
    <property name="jdbcUrl" value="${jdbc.url}"/>
    <property name="user" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
</bean>

3.使用JDBC的模板完成CRUD的操作

    1) 保存操作

@Test
// 保存操作
public void demo1(){
    jdbcTemplate.update("insert into account values (null,?,?)", "何菊花",10000d);
}

    2) 修改操作

@Test
// 修改操作
public void demo2(){
    jdbcTemplate.update("update account set name = ? ,money = ? where id = ?", "何巨涛",2000d,6);
}

    3) 删除操作

@Test
// 删除操作
public void demo3(){
    jdbcTemplate.update("delete from account where id = ?", 6);
}

    4) 查询操作

        ①查询某个属性

@Test
// 查询操作:
public void demo4(){
    String name = jdbcTemplate.queryForObject("select name from account where id = ?", String.class, 5);
    System.out.println(name);
}
 
@Test
// 统计查询
public void demo5(){
    Long count = jdbcTemplate.queryForObject("select count(*) from account", Long.class);
    System.out.println(count);
}

        ②查询返回对象或集合

@Test
// 封装到一个对象中
public void demo6(){
    Account account = jdbcTemplate.queryForObject("select * from account where id = ?", new MyRowMapper(), 5);
    System.out.println(account);
}
 
@Test
// 查询多条记录
public void demo7(){
    List<Account> list = jdbcTemplate.query("select * from account", new MyRowMapper());
    for (Account account : list) {
        System.out.println(account);
    }
}
 
class MyRowMapper implements RowMapper<Account>{
 
    @Override
    public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
        Account account = new Account();
        account.setId(rs.getInt("id"));
        account.setName(rs.getString("name"));
        account.setMoney(rs.getDouble("money"));
        return account;
    }
}

八、Spring的事务管理

1.Spring的事务管理的API

    1) PlatformTransactionManager

        平台事务管理器,是Spring用于管理事务的真正的对象。

DataSourceTransactionManager    :底层使用JDBC管理事务
HibernateTransactionManager     :底层使用Hibernate管理事务

    2) TransactionDefinition

        事务定义信息:用于定义事务的相关的信息,隔离级别、超时信息、传播行为、是否只读。

    3) TransactionStatus

        事务状态:用于记录在事务管理过程中,事务的状态的对象。

    4) 事务管理的API的关系

        Spring进行事务管理的时候,首先平台事务管理器根据事务定义信息进行事务的管理,在事务管理过程中,产生各种状态,将这些状态的信息记录到事务状态的对象中。

2.Spring的事务的传播行为

    1) 保证多个操作在同一个事务中

PROPAGATION_REQUIRED      :默认值,如果A中有事务,使用A中的事务,如果A没有,创建一个新的事务,将操作包含进来
PROPAGATION_SUPPORTS      :支持事务,如果A中有事务,使用A中的事务。如果A没有事务,不使用事务。
PROPAGATION_MANDATORY     :如果A中有事务,使用A中的事务。如果A没有事务,抛出异常。

    2) 保证多个操作不在同一个事务中

PROPAGATION_REQUIRES_NEW    :如果A中有事务,将A的事务挂起(暂停),创建新事务,只包含自身操作。如果A中没有事务,创建一个新事务,包含自身操作。
PROPAGATION_NOT_SUPPORTED   :如果A中有事务,将A的事务挂起。不使用事务管理。
PROPAGATION_NEVER           :如果A中有事务,报异常。

    3) 嵌套式事务

PROPAGATION_NESTED   :嵌套事务,如果A中有事务,按照A的事务执行,执行完成后,设置一个保存点,执行B中的操作,如果没有异常,执行通过,如果有异常,可以选择回滚到最初始位置,也可以回滚到保存点。

九、Spring模拟转账事务

1.搭建Spring的事务管理环境

    1) 创建Service接口和实现类

public class AccountServiceImpl implements AccountService {
 
    // 注入DAO:
    private AccountDao accountDao;
 
    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }
 
    @Override
    /**
     * from:转出账号
     * to:转入账号
     * money:转账金额
     */
    public void transfer(String from, String to, Double money) {
        accountDao.outMoney(from, money);
        accountDao.inMoney(to, money);
    }   
}

    2) 创建Dao的接口和实现类

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
 
    @Override
    public void outMoney(String from, Double money) {
        this.getJdbcTemplate().update("update account set money = money - ? where name = ?", money,from);
    }
 
    @Override
    public void inMoney(String to, Double money) {
        this.getJdbcTemplate().update("update account set money = money + ? where name = ?", money ,to);
    }
 
}

    3) 配置Service和DAO:交给Spring管理

<!-- 配置Service -->
<bean id="accountService" class="com.jzfblog.tx.demo1.AccountServiceImpl">
    <property name="accountDao" ref="accountDao"/>
</bean>
 
<!-- 配置DAO -->
<bean id="accountDao" class="com.jzfblog.tx.demo1.AccountDaoImpl">
    <!-- 配置一个连接池,就可以得到jdbc模板 -->
    <property name="dataSource" ref="dataSource"/>
</bean>

    4) 配置连接池和JDBC的模板

2.编程式事务(需要手动编写代码)

    1) 配置平台事务管理器

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

    2) Spring提供了事务管理的模板类

<!-- 配置事务管理的模板 -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
    <property name="transactionManager" ref="transactionManager"/>
</bean>

    3) 在业务层注入事务管理的模板

<!-- 配置Service============= -->
<bean id="accountService" class="com.jzfblog.tx.demo1.AccountServiceImpl">
    <property name="accountDao" ref="accountDao"/>
    <!-- 注入 事务管理的模板 -->
    <property name="trsactionTemplate" ref="transactionTemplate"/>
</bean>

    4) 编写事务管理的代码

public void transfer(final String from, final String to, final Double money) {
 
    trsactionTemplate.execute(new TransactionCallbackWithoutResult() {
        @Override
        protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
            accountDao.outMoney(from, money);
            int d = 1/0;
            accountDao.inMoney(to, money);
        }
    });
}

3.声明式事务管理(通过配置实现)---AOP

    1) XML方式的声明式事务管理

        ①引入aop的开发包

        ②配置事务管理器

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

        ③配置增强

<!-- 配置事务的增强=============================== -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <!-- 事务管理的规则 -->
        <!-- <tx:method name="save*" propagation="REQUIRED" isolation="DEFAULT"/>
        <tx:method name="update*" propagation="REQUIRED"/>
        <tx:method name="delete*" propagation="REQUIRED"/>
        <tx:method name="find*" read-only="true"/> -->
        <tx:method name="*" propagation="REQUIRED" read-only="false"/>
    </tx:attributes>
</tx:advice>

        ④AOP的配置

<!-- aop的配置 -->
<aop:config>
    <aop:pointcut expression="execution(* com.jzfblog.tx.demo2.AccountServiceImpl.*(..))" id="pointcut1"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
</aop:config>

    2) 注解方式的声明式事务管理

        ①引入aop的开发包

        ②配置事务管理器

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

        ③开启注解事务

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

        ④在业务层添加注解

@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)
public class AccountServiceImpl implements AccountService{}

打赏 蒋振飞

取消

感谢您的支持,我会继续努力的!

扫码支持
一分也是爱     一块不嫌多

点击 支付宝 或 微信 打赏蒋振飞

打开支付宝扫一扫,即可进行扫码打赏哦

评论列表