spring 学习笔记 。 AOP(切面编程) , IOC(容器) , DL(依赖注入),事务

Spring概述

 

初次使用spring配置文件xml

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"

       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="user" class="com.chapter01.User"></bean>

</beans>

测试

public void test(){

    //加载spring文件 ApplicationContext:应用上下文 ClassPathXmlApplicationContext:上下文xml类路径(xml的名称,xml里面包含了路径)    获取IOC容器

    ApplicationContext context = new ClassPathXmlApplicationContext("test1.xml");

    //获取配置创建对象

    User user = context.getBean("user", User.class);//获取User的class类,把接收到的object转化为User类

    System.out.println(user);

    user.add();

}

IOC容器(控制翻转)

创建对象的过程交给spring来管理,对象创建控制权由程序交给外部来处理。这种思想称为控制反转。IOC就是用于充当思想中的外部

原理

 

接口(beanFactory接口)

 

创建IOC容器

 

获取容器内的bean

 

引入外部属性文件

引入外部属性文件配置数据库连接池

1.创建外部配置文件

 

2.把外部properties文件引入到spring配置文件中(需要引入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:util="http://www.springframework.org/schema/util"

       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/util http://www.springframework.org/schema/util/spring-util.xsd

       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--引入外部标签上下文-->

    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>

    <!--配置连接池-->

        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">

            <property name="driverClassName" value="${driverClassName}"></property>

            <property name="url" value="${url}"></property>

            <property name="username" value="${username}"></property>

            <property name="password" value="${password}"></property>

        </bean>

</beans>

DI(依赖注入)(基于XML)

在IOC容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入(DI)。一个对象里面有个属性是其他对象,就需要把其他对象的bean注入到该对象的属性中原始方法是在该对象内new一个其他对象,但是这样耦合度太高了

内部属性(内部标签)

使用 set 方法进行注入(property标签)

(1)创建类,定义属性和对应的 set 方法

/**

 * 演示使用 set 方法进行注入属性

 */

public class Book {

    //创建属性

    private String bname;

    private String bauthor;

    //创建属性对应的 set 方法

    public void setBname(String bname) {

        this.bname = bname;

    }

    public void setBauthor(String bauthor) {

        this.bauthor = bauthor;

    }

}

(2)在 spring 配置文件配置对象创建,配置属性注入

<!--2 set 方法注入属性-->

<bean id="book" class="com.atguigu.spring5.Book">

<!--使用 property 完成属性注入

        name:类里面属性名称

        value:向属性注入的值

        -->

<property name="bname" value="易筋经"></property>

<property name="bauthor" value="达摩老祖"></property>

</bean>

使用有参数构造进行注入(constructor-arg标签)

(1)创建类,定义属性,创建属性对应有参数构造方法

package com.chapter01;

public class User {

    String name;

    public void setName(String name) {

        this.name = name;

    }

    public void add(){

        System.out.println(name);

    }

    public User(String name) {

        this.name = name;

    }

}

(2)在 spring 配置文件中进行配置

<!--3 有参数构造注入属性-->

<bean id="user" class="com.chapter01.User">

  <constructor-arg name="name" value="kevin"></constructor-arg>

</bean>

p名称空间注入

直接在标签里面注入值,省去了创建子节点标签,如constructor-arg标签property标签

 

其他符号属性

 

内部bean

<bean id="user" class="com.chapter01.User">

    <property name="name" value="kevin"></property>

    <!--内部bean要写到属性里面(用属性框包起来)-->

    <property name="dept" >

        <bean  id="dept" class="com.chapter01.Dept">

            <property name="name" value="学生会"></property>

        </bean>

    </property>

</bean>

外部bean(级联的一种)

<bean id="user" class="com.chapter01.User">

    <property name="name" value="kevin"></property>

    <property name="dept" ref="dept"></property>

</bean>

<bean id="dept" class="com.chapter01.Dept">

    <property name="name" value="学生"></property>

</bean>

级联操作

第一种:(参考外部bean)

第二种:

<bean id="user" class="com.chapter01.User">

    <property name="name" value="kevin"></property>

    <!--级联赋值-->

    <property name="dept" ref="dept"></property>

    <!--直接设置值,需要有get方法-->

    <property name="dept.name" value="校董会"></property>

</bean>

<bean id="dept" class="com.chapter01.Dept"></bean>

集合注入

数组,list,map,set,对象注入

<bean id="ALS" class="com.chapter01.Arr_List_Set">

    <!--数组元素注入-->

    <property name="arr">

        <array>

            <value>java</value>

            <value>c++</value>

        </array>

    </property>

    <!--List元素注入-->

    <property name="list">

        <list>

            <value>虹猫</value>

            <value>蓝兔</value>

        </list>

    </property>

    <!--map元素注入-->

    <property name="map">

        <map>

            <entry key="cctv6" value="电影"></entry>

            <entry key="cctv10" value="科教"></entry>

        </map>

    </property>

    <!--set元素注入-->

    <property name="set">

        <set>

            <value>苹果</value>

            <value>菠萝</value>

        </set>

    </property>

    <!--对象注入-->

    <property name="depts">

        <list>

            <ref bean="dept1"></ref>

            <ref bean="dept2"></ref>

        </list>

    </property>

</bean>

<!--创建多个dept对象方便引入-->

<bean id="dept1" class="com.chapter01.Dept">

    <property name="name" value="娃哈哈"></property>

</bean>

<bean id="dept2" class="com.chapter01.Dept">

    <property name="name" value="吉哈哈"></property>

</bean>

集合注入抽取

如果一个集合希望被其他bean调用的话,可以把集合提取出来(类似于提取为公共类)

<beans xmlns="http://www.springframework.org/schema/beans"

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

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

       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

        <util:list id="bookList">

            <value>三国演义</value>

            <value>水浒传</value>

            <value>红楼梦</value>

        </util:list>

        <bean id="book" class="com.chapter01.book">

            <property name="names" ref="bookList"></property>

        </bean>

bean管理(xml)

概念

什么是Bean管理

在xml文件(容器)中,对对象进行管理

bean管理操作有两种实现方式

基于xml配置文件方式实现和基于注解方式实现

实现

基于 xml 方式创建对象

      (1)在 spring 配置文件中,使用 bean 标签,标签里面添加对应属性,就可以实现对象创建

      (2)在 bean 标签有很多属性,介绍常用的属性

       id 属性:唯一标识

    class 属性:类全路径(包类路径)

      (3)创建对象时候,默认也是执行无参数构造方法完成对象创建

bean实例化方式

Spring 有两种类型 bean,一种普通 bean,另外一种工厂 bean(FactoryBean)

方式一 构造方法

在xml文件中通过类的构造方法来实例化其他bean类。(太繁琐)

方式二 工厂bean

创建一个实现了factoryBean接口的工厂类,用这个工厂类代理创建其他对象。然后再xml里面实例化这个工厂bean(所得到的bean是代理创建的对象,并不是这个工厂的bean)。(也实现了解耦)

 

bean的作用域(单双例)

默认单例

在spring里面,默认是单例模式

 

设置单实例还是多实例

spring 配置文件 bean 标签里面有属性(scope)用于设置单实例还是多实例

scope 属性值

第一个值( 默认值),singleton,表示是单实例对象。

第二个值 prototype,表示是多实例对象

 

singleton 和 prototype 区别

第一 singleton 单实例,prototype 多实例

第二 设置 scope 值是 singleton 时候,加载 spring 配置文件时候就会创建单实例对象 。设置 scope 值是 prototype 时候,不是在加载 spring 配置文件时候创建 对象,在调用getBean 方法时候创建多实例对象

bean的生命周期(带有后置处理器)

  1. (1)通过构造器创建 bean 实例(无参数构造)
  2. (2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
  3. (3)把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization (初始化前)
  4. (4)调用 bean 的初始化的方法(需要进行配置初始化的方法)
  5. (5)把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization(初始化后)
  6. (6)bean 可以使用了(对象获取到了)
  7. (7)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)

 

public Orders() {

    System.out.println("第一步 执行无参数构造创建 bean 实例");

}

private String oname;

public void setOname(String oname) {

    this.oname = oname;

    System.out.println("第二步 调用 set 方法设置属性值");

}

//创建执行的初始化的方法

public void initMethod() {

    System.out.println("第四步 执行初始化的方法");

}

//创建执行的销毁的方法

public void destroyMethod() {

    System.out.println("第七步 执行销毁的方法");

}

//配置xml

<bean id="orders" class="com.atguigu.spring5.bean.Orders" initmethod="initMethod" destroy-method="destroyMethod">

<property name="oname" value="手机"></property>

</bean>

//设置后置处理器

public class MyBeanPost implements BeanPostProcessor {

    @Override

    public Object postProcessBeforeInitialization(Object bean, String beanName)

            throws BeansException {

        System.out.println("第三步,在初始化之前执行的方法");

        return bean;

    }

    @Override

    public Object postProcessAfterInitialization(Object bean, String beanName)

            throws BeansException {

        System.out.println("第五步,在初始化之后执行的方法");

        return bean;

    }

}

<!--配置后置处理器xml-->

<bean id="myBeanPost" class="com.atguigu.spring5.bean.MyBeanPost"></bean>

//获取xml配置

 @Test

    public void testBean3() {

        ClassPathXmlApplicationContext context =

                new ClassPathXmlApplicationContext("bean.xml");

        Orders orders = context.getBean("orders", Orders.class);

        System.out.println("第六步 获取创建 bean 实例对象");

        System.out.println(orders);

        //手动让 bean 实例销毁

        context.close();

    }

xml的自动装配

bean将条件满足的外部bean自动引入。需要在bean标签里面申明两个属性

 bean 标签属性 autowire,配置自动装配 autowire 属性常用两个值: byName 根据属性名称注入 ,注入值 bean 的 id 值和类属性名称一样 byType 根据属性类型注入

代码演示

//根据属性名称引入

<bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byName">

<!--<property name="dept" ref="dept"></property>-->

</bean>

<bean id="dept" class="com.atguigu.spring5.autowire.Dept"></bean>

//根据类型引入,不能有多个相同属性

<bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byType">

<!--<property name="dept" ref="dept"></property>-->

</bean>

<bean id="dept" class="com.atguigu.spring5.autowire.Dept"></bean>

Bean管理(基于注解)

 

 

什么是注解

(1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值..)

(2)使用注解,注解作用在类上面,方法上面,属性上面

(3)使用注解目的:简化 xml 配置

基于注解实现对象的创建

Spring 针对 Bean 管理中创建对象提供注解

(1)@Component(2)@Service(3)@Controller(4)@Repository

* 上面四个注解功能是一样的,都可以用来创建 bean 实例

实现步骤

第一步:到spring文件包里引入aop.jar包(引入依赖)

 

第二步:开启组件扫描

<beans xmlns="http://www.springframework.org/schema/beans"

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

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

       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/util http://www.springframework.org/schema/util/spring-util.xsd

       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--开启组件扫描 填入需要使用到注解的包-->

    <context:component-scan base-package="com.chapter01"></context:component-scan>

</beans>

第三步:创建类并在类上添加注解

@Component(value = "testBook")//给类起别名,默认是类名首字母小写 相当于xml<!-- id="testBook" ...

public class book {

    private List<String> names;

    public void show(){

        System.out.println(names);

    }

}

//调用

@Test

public void test(){

    //加载spring文件 ApplicationContext:应用上下文 ClassPathXmlApplicationContext:上下文xml类路径(xml的名称,xml里面包含了路径)

    ApplicationContext context = new ClassPathXmlApplicationContext("test1.xml");

    //获取配置创建对象

   book books  = context.getBean("testBook", book.class);//获取User的class类,把接收到的object转化为User类

    System.out.println(books);

    books.show();

}

第四:开启组件扫描细节配置(设置扫描过滤器)

<!--示例 1 use-default-filters="false" 表示现在不使用默认 filter,自己配置 filter。 context:include-filter ,设置扫描哪些内容-->

<context:component-scan base-package="com.atguigu" use-defaultfilters="false">

<context:include-filter type="annotation"

        expression="org.springframework.stereotype.Controller"/>

</context:component-scan>

<!--示例 2下面配置扫描包所有内容

  context:exclude-filter: 设置哪些内容不进行扫描-->

<context:component-scan base-package="com.atguigu">

<context:exclude-filter type="annotation"

        expression="org.springframework.stereotype.Controller"/>

</context:component-scan>

基于注解实现属性注入

spring针对属性注入的注解

@Autowired:根据属性类型进行自动装配

@Qualifier:根据名称进行注入(@Qualifier 需要和上面@Autowired 一起使用)

@Resource:可以根据类型注入,可以根据名称注入

@Value:注入普通类型属性

//第一种 @Autowired:根据属性类型进行自动装配

@Component

public class Dept {

    //定义 dao 类型属性 。不需要添加 set 方法 。添加注入属性注解

    private String name;

    @Autowired

    private book book;

}

//第二种@Qualifier:根据名称进行注入(@Qualifier 需要和上面@Autowired 一起使用)

@Component

public class Dept {

    private String name;

   @Autowired

    @Qualifier(value = "testBook")

    private book book;

}

//第三种@Resource:可以根据类型注入,可以根据名称注入

@Component

public class Dept {

    private String name;

    @Resource(name = "testBook")

    //不写值默认是根据类型注入,写了就是根据名字(id)进行注入

    private book book;

}

//第四种@Value:注入普通类型属性

@Component

public class Dept {

    @Value( value = "kevin")

    private String name;

 }

完全注解开发

 

把xml配置文件用注解类(配置类)来替代

1.创建配置类,来代替配置文件

@Configuration//标注为配置类

@ComponentScan(basePackages = {"com.chapter01"})//开启扫描(把扫描移到注解配置类里面)

public class SpringConfig {

}

2.修改测试列的加载语句。改为new一个配置类

@Test

public void test(){

    //加载spring文件 ApplicationContext:应用上下文 AnnotationConfigApplicationContext:注解配置应用上下文xml类路径(xml的名称,xml里面包含了路径)

    ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);//通过反射得到注解类

    //获取配置创建对象

   Dept dept  = context.getBean("dept", Dept.class);//获取User的class类,把接收到的object转化为User类

    System.out.println(dept);

    dept.show();

}

注解读取properties配置文件

@Value一般会被用在从properties配置文件中读取内容进行使用,具体如何实现?

步骤1:resource下准备properties文件

jdbc.properties

步骤2: 使用注解加载properties配置文件

在配置类上添加@PropertySource注解

@Configuration@ComponentScan("com.itheima")

@PropertySource("jdbc.properties")

public class SpringConfig {}

步骤3:使用@Value读取配置文件中的内容

@Repository("bookDao")

public class BookDaoImpl implements BookDao {

    @Value("${name}")

    private String name;

    public void save() {

        System.out.println("book dao save ..." + name);

    }

}

第三方注解bean管理

方式

 

第三方bean简单类型的依赖注入

 

第三方bean引用类型依赖注入

写一个形参就行

 

AOP(面向切面)

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

(2)通俗描述:不通过修改源代码方式,在主干功能里面添加新功能

(3)不修改源代码进行功能增强

底层原理

AOP底层使用了动态代理模式(可以转到设计模式笔记里面的代理模式,这里做简单叙述)

动态代理有两种代理

第一种(基于接口的JDk动态代理)

 

第二种(基于继承的CGLIB动态代理模式)

 

AOP操作术语

假设一个类{方法A,B,C...}

1.连接点

类里面可以被增强的方法称作链接点(可以被连接)

2.切入点(@pointcut)

实际被增强的方法,称为切入点

3.通知(增强)(通知类)

(1)实际用于增强的逻辑代码称为通知(增强)

(2)通知的多种类型

前置通知:在方法前面实现增强

后置通知:在方法后面实现增强

环绕通知:在方法前后都进行了增强

 

注:环绕通知注意细节

 

异常通知:出现异常执行才执行的增强

最终通知:不管出不出异常都会执行的增强

4.切面

把通知应用到切入点的过程。(将增强代码(面)插入需要增强的方法(切入点)

代码实现

1引入依赖

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"

         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>

    <artifactId>spring2</artifactId>

    <version>1.0-SNAPSHOT</version>

    <properties>

        <maven.compiler.source>8</maven.compiler.source>

        <maven.compiler.target>8</maven.compiler.target>

    </properties>

    <dependencies>

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-context</artifactId>

            <version>5.2.10.RELEASE</version>

        </dependency>

        <dependency>

            <groupId>org.aspectj</groupId>

            <artifactId>aspectjweaver</artifactId>

            <version>1.9.4</version>

        </dependency>

    </dependencies>

</project>

2创建接口实现类

  1. 开启注解

package com.kevin.dao.impl;

import com.kevin.dao.BookDao;

import org.springframework.stereotype.Repository;

@Repository

public class BookDaoImpl implements BookDao {

    public  void save(){

       // System.out.println(System.currentTimeMillis());

        System.out.println("book dao save ...");

    }

    public void update(){

        System.out.println("book dao update ...");

    }

}

3创建配置类

  1. 定义配置类
  2. 开启注解扫描
  3. 启动切面自动代理

package com.kevin.config;

import org.springframework.context.annotation.ComponentScan;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration

@ComponentScan("com.kevin")

@EnableAspectJAutoProxy

public class SpringConfig {

}

4定义切面和写入通知(增强方法)

  1. 开启注解
  2. 声明这是一个切面类
  3. 声明切入点
  4. 设置通知类型和绑定关系

package com.kevin.aop;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.annotation.Pointcut;

import org.springframework.stereotype.Component;

@Component

@Aspect

public class MyAdvice {

    @Pointcut("execution(void com.kevin.dao.BookDao.update())")

    private void pt(){}

    @Before("pt()")

    public void method(){

        System.out.println(System.currentTimeMillis());

    }

}

5测试代码

  1. 获取容器(指明配置类)
  2. 获取bean
  3. 调用方法

package com.kevin;

import com.kevin.config.SpringConfig;

import com.kevin.dao.BookDao;

import org.springframework.context.ApplicationContext;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App {

    public static void main(String[] args) {

        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

        BookDao bookDao = ctx.getBean(BookDao.class);

        bookDao.save();

    }

}

AOP的工作流程

 

AOP切入点表达式

(1)切入点表达式格式:动作关键字(访问修饰符  返回值 路径(参数)异常名)

 

表达式通配符

 

书写技巧

 

AOP通知获取数据

从原始方法获取参数

 

获取返回值

 

通知获取异常

 

数据处理代码实现

1.引入依赖,创建配置类

2.创建service接口和实现类

@Service

public class ResourcesServiceImpl implements ResourcesService {

    @Autowired

    private ResourcesDao resourcesDao;

    @Override

    public boolean openURL(String url, String password) {

        System.out.println(password.length());

        //在这调用数据层接口

        return resourcesDao.readResources(url,password);

    }

}

3创建数据层(Dao)接口和实现类

@Repository

public class ResourcesDaoImpl implements ResourcesDao {

    @Override

    public boolean readResources(String url, String password) {

        //模拟校验

        return password.equals("root");

    }

}

4.创建aop对方法实现前进行数据的处理

@Component

@Aspect

public class DataAdvice {

    @Pointcut("execution(boolean com.kevin.Service.*Service.*(*,*))")

    private void pt(){}

    @Around("pt()")

    public Object trimStr(ProceedingJoinPoint pjp) throws Throwable {

        //在原有方法前对字符串进行处理

        //获取参数

        Object[] args = pjp.getArgs();

        for (int i =0;i<args.length;i++){

            //判断是否为字符串

            if (args[i].getClass().equals(String.class)){

                //处理字符串

                args[i] = args[i].toString().trim();

            }

        }

        //执行原有方法,把改完的参数放回去

        Object proceed = pjp.proceed(args);

        //返回方法值

        return proceed;

    }

}

5.创建测试类进行测试

public class App {

    public static void main(String[] args) {

        ApplicationContext app =new AnnotationConfigApplicationContext(SpringConfig.class);

        ResourcesService rs = app.getBean(ResourcesService.class);

        boolean flag= rs.openURL("https://pan.baidu.com/haha", "root ");

        System.out.println(flag);

    }

}

spring-mybatis整合

实现思路 :dataSource<factory<session<dao<service

把mybatis一些创建对象引入资源等事情交给spring容器去完成,mybatis配置文件写一些设置就行

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE configuration

        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"

        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<!-- 配置文件的根元素 -->

<configuration>

    <!--设置:定义mybatis的一些全局属性-->

    <settings>

    <!--log4j-->

    <!--<setting name="logImpl" value="LOG4J"/>-->

<!--        自动映射行为  full全映射 none写啥映射啥  默认是partial 比none级别高-->

        <setting name="autoMappingBehavior" value="FULL"/>

        <setting name="jdbcTypeForNull" value="NULL"/>

        <setting name="cacheEnabled" value="ture"/>

    </settings>

    <!--配置别名-->

    <typeAliases>

        <package name="com.user.model"/>

        <package name="com.user.dao"/>

    </typeAliases>   

    <plugins>

        <plugin interceptor="com.github.pagehelper.PageInterceptor">

            <property name="helperDialect" value="oracle"/>

        </plugin>

    </plugins>

<!--    数据库环境交给spring配置-->

</configuration>

基础配置

完成model层,再编写接口以及实现类,编写mapper.xml文件

model

@Data

@ToString

@NoArgsConstructor

@AllArgsConstructor

public class SmbmsUser {

  private String id;

  private String usercode;

  private String username;

  private String userpassword;

  private String gender;

  private java.sql.Date birthday;

  private String phone;

  private String address;

  private String userrole;

  private String createdby;

  private java.sql.Date creationdate;

  private String modifyby;

  private java.sql.Date modifydate;

}

接口

List<SmbmsUser> getUserList() throws IOException;

SmbmsUser getUser(String id) throws IOException;

Integer addUser(SmbmsUser user);

Integer update(SmbmsUser user);

Integer delete(String id);

实现类

public class UserDao implements IUserDao {

    String nameSpace = "com.user.dao.IUserDao";

//    由容器注入session

    private SqlSessionTemplate sqlSession;

    public SqlSessionTemplate getSqlSession() {

        return sqlSession;

    }

    public void setSqlSession(SqlSessionTemplate sqlSession) {

        this.sqlSession = sqlSession;

    }

    @Override

    public List<SmbmsUser> getUserList() throws IOException {

        List<SmbmsUser> users = sqlSession.selectList(nameSpace + ".getUserList", SmbmsUser.class);

        return users;

    }

    @Override

    public SmbmsUser getUser(String id) throws IOException {

        SmbmsUser user = sqlSession.selectOne(nameSpace + ".getUser", id);

        return user;

    }

    @Override

    public Integer addUser(SmbmsUser user) {

        int insert = sqlSession.insert(nameSpace + ".addUser", user);

//        手动提交

        sqlSession.commit();

        return insert;

    }

    @Override

    public Integer update(SmbmsUser user) {

        int update = sqlSession.update(nameSpace + ".update", user);

        sqlSession.commit();

        return update;

    }

    @Override

    public Integer delete(String id) {

        int delete = sqlSession.delete(nameSpace + ".delete", id);

        sqlSession.commit();

        return  delete;

    }

}

mapper.xml

<?xml version="1.0" encoding="utf-8" ?>

<!DOCTYPE mapper

        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.user.dao.IUserDao">

        <resultMap id="user" type="smbmsUser">

            <id property="id" column="ID"></id>

            <result property="name" column="USERNAME"></result>

        </resultMap>

        <select id="getUserList" resultType="com.user.model.SmbmsUser">

            select * from SMBMS_USER

        </select>

        <select id="getUser" resultMap="user" parameterType="java.lang.String">

            select * from SMBMS_USER where id = #{id}

        </select>

   

        <insert id="addUser" parameterType="smbmsUser">

            <![CDATA[

            insert into SMBMS_USER

            (ID,USERCODE,USERNAME,USERPASSWORD,GENDER,BIRTHDAY,PHONE,ADDRESS,USERROLE,CREATEDBY,CREATIONDATE)

            values (#{id},#{usercode},#{name},#{userpassword},#{gender},#{birthday},#{phone},#{address},#{userrole},#{createdby},#{creationdate})

]]>

        </insert>

        <update id="update" parameterType="smbmsUser">

            <![CDATA[

            update SMBMS_USER

            set

                USERCODE=#{usercode},

                USERNAME=#{name},

                USERPASSWORD=#{userpassword},

                GENDER=#{gender},

                BIRTHDAY=#{birthday},

                PHONE=#{phone},

                ADDRESS=#{address},

                USERROLE=#{userrole},

                MODIFYBY=#{modifyby},

                MODIFYDATE=#{modifydate}

            where id = #{id}

]]>

        </update>

        <delete id="delete" parameterType="string">

<![CDATA[

            delete from SMBMS_USER where ID= #{id}

            ]]>

        </delete>

<!--    #{} 占位符,用于预编译-->

<!--    ${} sql拼接-->

</mapper>

在spring容器xml里面配置mybatis所需要的类与资源

1 引入外部文件(数据库配置文件)

<!--   1 引入外部文件-->

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

        <property name="location" value="druid.properties"></property>

    </bean>

2 配置数据源/池(value值需要与配置文件里面一致)

<!--  2  配置数据源/池-->

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">

        <property name="username" value="${username}"></property>

        <property name="password" value="${password}"></property>

        <property name="driverClassName" value="${driverClassName}"></property>

        <property name="url" value="${url}"></property>

        <property name="initialSize" value="${initialSize}"></property>

        <property name="maxActive" value="${maxActive}"></property>

        <property name="minIdle" value="${minIdle}"></property>

        <property name="maxWait" value="${maxWait}"></property>

    </bean>

3 创建SqlSessionFactoryBean 建立数据库会话的工厂

<!--   3 创建SqlSessionFactoryBean工厂-->

    <bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">

        <!--3.1  配置连接池-->

        <property name="dataSource" ref="dataSource"></property>

        <!--3.2 配置mybatis文件-->

        <property name="configLocation" value="mybatis-config.xml"></property>

        <!--3.3 配置映射文件 因为配置文件不止一个,所以要用list-->

        <property name="mapperLocations" >

            <list>

                <value>com/user/dao/mapper/userDaoMapper.xml</value>

            </list>

        </property>

    </bean>

4 创建session模型,用于注入到方法

<!--   4 创建会话模型,用于注入到方法-->

    <bean id="sessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">

        <constructor-arg ref="factory"></constructor-arg>

    </bean>

5 创建dao,service    bean对象

<!--    创建dao,service    bean对象-->

    <bean id="userDao" class="com.user.dao.Imp.UserDao">

        <property name="sqlSession"  ref="sessionTemplate"></property>

    </bean>

   

    <bean id="userService" class="com.user.service.Imp.UserService">

        <property name="userDao" ref="userDao"></property>

    </bean>

</beans>

如果dao接口没有实现类

4原第四步可以省略,直接传入第三步的session工厂给MapperFactory,让MapperFactory创建dao接口的子类(与原实现类为兄弟关系,要用dao接口接收),这个子类顶替原实现类,原实现类方法里面就只有创建session,然后用session去查询数据,这个步骤可以让容器来完成。

4 创建MapperFactoryBean

<!--创建MapperFactoryBean,方便被service层调用-->

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">

<!--4.1 设置要实现的接口-->

    <property name="mapperInterface" value="com.user.dao.IUserDao"></property>

<!--4.2 引入前面创建好的工厂,来创建会话,也可以传入创建好的session模型-->

    <property name="sqlSessionFactory" ref="factory"></property>

</bean>

5 创建service

<bean id="userService" class="com.user.service.Imp.UserService">

    <property name="userDao" ref="userMapper"></property>

</bean>

注解方式

4 配置MapperScannerConfigurer

 自动扫描路径下的mapper接口,自动注册MapperFactoryBean(dao接口的子实现类)

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

        <property name="basePackage" value="com.*.dao"></property>

    </bean>

5 开启注解扫描

<!--开启注解扫描-->

<context:component-scan base-package="com"></context:component-scan>

6 给service层打上@service和属性自动装配

@Service

public class UserService implements IUserService {

    @Autowired

    private IUserDao userDao;

    public IUserDao getUserDao() {

        return userDao;

    }

    public void setUserDao(IUserDao userDao) {

        this.userDao = userDao;

    }

    @Override

    public List<SmbmsUser> getUserList() throws IOException {

        return userDao.getUserList();

    }

事务

事务四种隔离级别

  1. Read Uncommited,读未提交,即一个事务可以读取另一个未提交事务的数据;并发操作会导致脏读
  2. Read Commited,读操作,即一个事务要等到另一个事务提交后才能读取数据;解决脏读问题;并发操作会导致不可重复读
  3. Repeatable Read,重复读,即开始读取数据(事务开启)时,不再允许修改操作;解决不可重复读问题;并发操作会导致幻读(对应insert操作)
  4. Serializable,序列化,最高的事务隔离级别,该级别下,事务串行化顺序执行;避免脏读、不可重复读与幻读;但是该级别效率低下,比较消耗数据库性能,一般不用。

 

事务七种传播机制

  1. REQUIRE组
    1. 1.REQUIRED:当前存在事务则使用当前的事务, 当前不存在事务则创建一个新的事务
    2. 2.REQUIRES_NEW:创建新事务, 如果已经存在事务, 则把已存在的事务挂起
  2. SUPPORT组
    1. 1.SUPPORTS:支持事务. 如果当前存在事务则加入该事务, 如果不存在事务则以无事务状态执行
    2. 2.NOT_SUPPORTED:不支持事务. 在无事务状态下执行,如果已经存在事务则挂起已存在的事务
  3. Exception组
    1. 1.MANDATORY:必须在事务中执行, 如果当前不存在事务, 则抛出异常
    2. 2.NEVER: 不可在事务中执行, 如果当前存在事务, 则抛出异常
  4. NESTED:嵌套事务. 如果当前存在事务, 则嵌套执行, 如果当前不存在事务, 则开启新事务

实现事务添加的spring.xml配置文件

<!--  配置事务  -->

    <!--1 配置事务管理器的bean  -->

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

        <!--传入数据源-->

        <property name="dataSource" ref="dataSource"></property>

    </bean>

    <!--2 配置事务增强  -->

    <tx:advice id="txAdvice" transaction-manager="transactionManager">

        <tx:attributes>

            <tx:method name="add*" isolation="DEFAULT" propagation="REQUIRED"/>

            <tx:method name="get*" isolation="DEFAULT" propagation="REQUIRED"/>

            <tx:method name="delete*" isolation="DEFAULT" propagation="REQUIRED"/>

            <tx:method name="update*" isolation="DEFAULT" propagation="REQUIRED"/>

        </tx:attributes>

    </tx:advice>

    <!--3 配置切面  将事务增强与切入点进行绑定  -->

    <aop:config>

        <!--2.1 配置切入点  -->

        <aop:pointcut id="pointcut" expression="execution(public * com.*.service.*.*(..))"/>

        <!--2.2 将两者进行绑定  -->

        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"></aop:advisor>

    </aop:config>

代码实现

未实现事务的转账

1.1 引入依赖

1.2 创建于数据库表格对应的映射表

public class Account implements Serializable {

    private Integer id;

    private String name;

    private Double money;

    //set..get...

}

1.3 创建sql语句接口

package com.kevin.dao;

import org.apache.ibatis.annotations.Param;

import org.apache.ibatis.annotations.Update;

public interface AccountDao {

    @Update("update spring3 set money = money + #{money} where name = #{name}")

    void inMoney(@Param("name") String name, @Param("money") Double money);

    @Update("update spring3 set money = money - #{money} where name = #{name}")

    void outMoney(@Param("name") String name, @Param("money") Double money);

}

1.4 创建service接口和实现了

@Transactional

public interface AccountService {

    /**

     * 转账操作

     * @param out 传出方

     * @param in 转入方

     * @param money 金额

     */

    public void transfer(String out,String in ,Double money) ;

}

//实现类

@Service

public class AccountServiceImpl implements AccountService {

    @Autowired

    private AccountDao accountDao;

    public void transfer(String out,String in ,Double money) {

        accountDao.outMoney(out,money);

        int i = 1/0;

        accountDao.inMoney(in,money);

    }

}

1.5 添加jdbc文件

jdbc.driver=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/kevin_01?useSSL=false

jdbc.username=root

jdbc.password=232517

1.6 创建jdbc配置类

import javax.sql.DataSource;

public class JDBCConfig {

    @Value("${jdbc.driver}")

    private String driver;

    @Value("${jdbc.url}")

    private String url;

    @Value("${jdbc.username}")

    private String userName;

    @Value("${jdbc.password}")

    private String password;

    @Bean

    public DataSource dataSource(){

        DruidDataSource ds = new DruidDataSource();

        ds.setDriverClassName(driver);

        ds.setUrl(url);

        ds.setUsername(userName);

        ds.setPassword(password);

        return ds;

    }

1.7 创建Mybatis配置类

import javax.sql.DataSource;

public class MybatisConfig {

    @Bean

    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){

        SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();

        ssfb.setTypeAliasesPackage("com.kevin.domain");

        ssfb.setDataSource(dataSource);

        return ssfb;

    }

    @Bean

    public MapperScannerConfigurer mapperScannerConfigurer(){

        MapperScannerConfigurer msc = new MapperScannerConfigurer();

        msc.setBasePackage("com.kevin.dao");

        return msc;

    }

}

1.8 创建容器配置类

@Configuration

@ComponentScan("com.kevin")

@PropertySource("classpath:jdbc.properties")

@Import({JDBCConfig.class,MybatisConfig.class})

public class SpringConfig {

}

1.9 编写测试类

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(classes = SpringConfig.class)

public class AccountServiceTest {

    @Autowired

    private AccountService accountService;

    @Test

    public void testTransfer() throws IOException {

        accountService.transfer("tom","jery",100D);

    }

}

添加事务对以上代码改进

2.1 给方法接口添加事务

//2.1 开启注解事务

@Transactional

public interface AccountService {

    /**

     * 转账操作

     * @param out 传出方

     * @param in 转入方

     * @param money 金额

     */

    public void transfer(String out,String in ,Double money) ;

}

2.2 配置事务管理器,mybatis使用的是jdbc事务

public class JDBCConfig {

    @Value("${jdbc.driver}")

    private String driver;

    @Value("${jdbc.url}")

    private String url;

    @Value("${jdbc.username}")

    private String userName;

    @Value("${jdbc.password}")

    private String password;

    @Bean

    public DataSource dataSource(){

        DruidDataSource ds = new DruidDataSource();

        ds.setDriverClassName(driver);

        ds.setUrl(url);

        ds.setUsername(userName);

        ds.setPassword(password);

        return ds;

    }

    //2.2 配置事务管理器,mybatis使用的是jdbc事务

    @Bean

    public PlatformTransactionManager transactionManager(DataSource dataSource){

        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();

        transactionManager.setDataSource(dataSource);

        return transactionManager;

    }

}

2.3 开启注解事务驱动

@Configuration

@ComponentScan("com.kevin")

@PropertySource("classpath:jdbc.properties")

@Import({JDBCConfig.class,MybatisConfig.class})

//2.3 开启注解式事务驱动

@EnableTransactionManagement

public class SpringConfig {

}

事务角色

事务管理员

事务发起方,在spring中通常指代业务层开启事务的方法

事务协调员

加入事务方,在spring中通常指代数据层方法,也可以指代业务层方法

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值