Spring框架总结

Spring框架的概述

第一次写博客,总结一下最近跟着b站尚硅谷学的spring5框架,并且记录一下自己的学习过程

1、Spring 是轻量级的开源的 JavaEE 框架 

2、Spring 可以解决企业应用开发的复杂性 

3、Spring 有两个核心部分:IOC 和 Aop 

(1)IOC:控制反转,把创建对象过程交给 Spring 进行管理 

(2)Aop:面向切面,不修改源代码进行功能增强 

4、Spring 特点 

(1)方便解耦,简化开发 

(2)Aop 编程支持 

(3)方便程序测试 

(4)方便和其他框架进行整合 

(5)方便进行事务操作 

(6)降低 API 开发难度

总的来说spring框架重点掌握Aop和Ioc对之前学的javaEE和jdbc等技术进行了简化和降低代码的耦合度。

IOC

IOC的概念


1、什么是 IOC 

(1)控制反转,把对象创建和对象之间的调用过程,交给 Spring 进行管理 

(2)使用 IOC 目的:为了耦合度降低 

(3)做入门案例就是 IOC 实现 

IOC中的两个重要接口:
Spring 提供 IOC 容器实现两种方式:(两个接口) 
(1) BeanFactory:IOC 容器基本实现,是 Spring 内部的使用接口,不提供开发人员进行使用 
【 BeanFactory接口说明:加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象】 
(2) ApplicationContext:BeanFactory 接口的子接口,提供更多更强大的功能,一般由开发人 员进行使用 
【ApplicatuionContext接口的说明:加载配置文件时候就会把在配置文件对象进行创建】

ApplicationContext的两个重要实现类:

  • FileSystemXmlApplicationContext:xml文件在系统盘里的全路径

  • ClassPathXmlApplicationContext:src下的xml文件的路径


IOC操作Bean管理(基于xml方式)


1、基于xml的方式创建对象

<bean id="user" class="spring_test.User"></bean>

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

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

  • id属性:唯一标识

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

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

2、基于xml的方式进行属性的注入

之前对属性注入值的方式:

​
public class Book {
    private String bname;
    private String bauthor;

    public void setBname(String bname) {
        this.bname = bname;
    }

    public void setBauthor(String bauthor) {
        this.bauthor = bauthor;
    }

    public void add1(){
        System.out.println(bname + "::" + bauthor);
    }

    public static void main(String[] args) {
        Book book = new Book();
        book.setBname("如何自学java");
        book.setBauthor("b站老师");
    }
}

​

用xml的方式:

(1)创建类,创建对应的set()方法

public class Book {
    private String bname;
    private String bauthor;

    public void setBname(String bname) {
        this.bname = bname;
    }

    public void setBauthor(String bauthor) {
        this.bauthor = bauthor;
    }
}

(2) 在 spring 配置文件配置对象创建,配置属性注入【使用property标签完成属性注入,name:类里的属性名称,value:向属性注入的值】

​
<bean id="book" class="spring_test.Book">
    <property name="bname" value="java如何自学"></property>
    <property name="bauthor" value="b站老师"></property>
</bean>

​

(3)同样的在测试类中先加载配置文件,再获取创建的配置对象:配置文件对象.getBean("spring配置文件的id值","通过反射获取类")

@Test
public void test(){
    //1、先加载配置文件xml
    ApplicationContext context = new ClassPathXmlApplicationContext("bean_1.xml");

    //获取创建的配置对象
    User user = context.getBean("book",Book.class);
}

3、注入属性实际应用到【外部bean的与内部bean】

使用案例进行说明【基于javaEE的写法,创建dao包和service包】:

(1)创建两个类 service 类和 dao 类 

(2)在 service 调用 dao 里面的方法 

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

第一步:创建dao包,包里创建BookDao接口 和 BookDaoImpl类

BookDao接口:

public interface BookDao {
    public void add2();
}

BookDaoImpl类:

public class BookDaoImpl implements BookDao{
    @Override
    public void add2() {
        System.out.println("dao add ....");
    }
}

第二步:创建service包,包中创建BookService接口 和 BookServiceImpl类

BookService接口:

public interface BookService {
    public void add1();
}

BookServiceImpl类:

public class BookServiceImpl implements BookService{
    private BookDao bookDao;

    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    @Override
    public void add1() {
        System.out.println("service add.....");
        bookDao.add2();
    }
}

第三步:配置xml文件【实现注入】

外部bean的做法:

<bean id="bookServiceImpl" class="spring_test.service.BookServiceImpl">
    <property name="bookDao" ref="bookDaoImpl"></property>
    <!--这种做法是外部bean:就是说这里的property属性是一个类,所以要在外面再创建一个类,用ref把类注入进去-->
</bean>
<bean id="bookDaoImpl" class="spring_test.dao.BookDaoImpl"></bean>

內部bean的做法:

<bean id="bookServiceImpl" class="spring_test.service.BookServiceImpl">
    <property name="bookDao">
    <bean id="bookDaoImpl" class="spring_test.dao.BookDaoImpl"></bean>
    </property>
</bean>

最后一步:建测试类进行测试:

@Test
public void test(){
    //1、先加载配置文件xml
    ApplicationContext context = new ClassPathXmlApplicationContext("bean_1.xml");

    //获取创建的配置对象
    BookServiceImpl bookService = context.getBean("bookServiceImpl",BookServiceImpl.class);
    System.out.println(bookService);
    bookService.add1();
}

输出结果为:

4、IOC 操作 Bean 管理(xml 注入集合属性)

1、注入数组类型属性

2、注入 List 集合类型属性 

3、注入 Map 集合类型属性

继续使用案例进行分析:

(1)创建类,定义数组、list、map、set 类型属性,生成对应 set 方法

public class CollectionTest {
    private String[] course;
    private List<String> list;
    private Map<String,String> map;
    private Set<String> sets;

    public void setCourse(String[] course) {
        this.course = course;
    }

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

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

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

    public void test(){
        System.out.println(Arrays.toString(course));
        System.out.println(list);
        System.out.println(map);
        System.out.println(sets);
    }
}

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

<bean id="CollectionTest" class="spring_test.collectiontype.CollectionTest">
    <property name="course">
        <array>
            <value>java基础课程</value>
            <value>python基础课程</value>
        </array>
    </property>

    <property name="list">
        <list>
            <value>张三</value>
            <value>李四</value>
        </list>
    </property>

    <property name="map">
        <map>
            <entry key="JAVA" value="java"></entry>
            <entry key="PHP" value="php"></entry>
        </map>
    </property>

    <property name="sets">
        <set>
            <value>mysql</value>
            <value>spring</value>
        </set>
    </property>
</bean>

(3)创建测试类进行测试

@Test
public void test1(){
    //1、先加载配置文件xml
    ApplicationContext context = new ClassPathXmlApplicationContext("bean_3.xml");

    //获取创建的配置对象
    CollectionTest collectionTest = context.getBean("CollectionTest",CollectionTest.class);
    collectionTest.test();
}

细节一:在集合里面设置对象类型值

例如:

private List<Book> lists; //这里的Book是一个类

xml中的配置:【注意这里是在上面的<bean id="collectionTest" ...></bean>这个标签里添加一下代码】

<property name="lists">
    <list>
        <ref bean="Book1"></ref>
        <ref bean="Book2"></ref>
    </list>
</property>

<bean name="Book1" class="spring_test.Book">
    <property name="bname" value="java如何学"></property>
</bean>
<bean name="Book2" class="spring_test.Book">
    <property name="bname" value="python如何学"></property>
</bean>

细节二:把集合注入部分提取出来【以提取list为例】

首先引用名称空间util

例:这里的ref 是将上面的booklist放进去所要使用的类中的list -- > 这样就能实现哪个部分需要就用

<!--提取list集合类型属性注入-->
<util:list id="booklist">
    <value>java</value>
    <value>python</value>
    <value>css</value>
</util:list>

<!--提取list集合类型属性注入使用-->
<bean id="Book" class="spring_test.collectiontype.CollectionTest">
    <property name="list" ref="booklist"></property>  //这里的ref 是将上面的booklist放进去所要使用的类中的list
</bean>

5、IOC 操作 Bean 管理(FactoryBean)

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

2、普通 bean:在配置文件中定义 bean 类型就是返回类型 

3、工厂 bean:在配置文件定义 bean 类型可以和返回类型不一样 

  • 第一步 创建类,让这个类作为工厂 bean,实现接口 FactoryBean 

  • 第二步 实现接口里面的方法,在实现的方法中定义返回的 bean 类型

使用案例代码进行分析

这里我定义一个类,实现FactoryBean接口,注意FactoryBean要写泛型<返回的类>

public class Mybean implements FactoryBean<Book> {
        //接口的实现类
    @Override
    public Book getObject() throws Exception {
        Book book = new Book();
        book.setBname("java如何学");
        return book;
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }
}

配置文件xml【这里配置的是Mybean类,若实现Factory接口则会放回其他类型】

<bean id="mybean" class="spring_test.bean.Mybean"></bean>

 (3)创建测试类进行测试

@Test
public void test2(){
    //1、先加载配置文件xml
    ApplicationContext context = new ClassPathXmlApplicationContext("bean_5.xml");

    //获取创建的配置对象
    Book mybean = context.getBean("mybean", Book.class);
    System.out.println(mybean);
}

 

6、单实例和多实例

1、在 Spring 里面,设置创建 bean 实例是单实例还是多实例 

2、在 Spring 里面,默认情况下,bean 是单实例对象

如何设置单实例还是多实例 

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

(2)scope 属性值 第一个值 默认值,singleton,表示是单实例对象 第二个值 prototype,表示是多实例对象

 

<bean id="Book" class="spring_test.collectiontype.CollectionTest" scope="prototype">
    <property name="list" ref="booklist"></property>
</bean>

(3)singleton 和 prototype 区别 

第一 singleton 单实例,prototype 多实例 

第二 设置 scope 值是 singleton 时候,加载 spring 配置文件时候就会创建单实例对象 

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

IOC 操作 Bean 管理(bean 生命周期)

1、生命周期 

(1)从对象创建到对象销毁的过程 

2、bean 生命周期 (五步)

(1)通过构造器创建 bean 实例(无参数构造) 

(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法) 

(3)调用 bean 的初始化的方法(需要进行配置初始化的方法) 

(4)bean 可以使用了(对象获取到了) 

(5)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法) 

3、演示 bean 生命周期

 编写一个Order类:

public class Order {
    private String oname;

    public Order() {
        System.out.println("第一步,调用空参构造器");
    }

    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="order" class="spring_test.bean.Order" init-method="initMethod" destroy-method="destroyMethod">
    <property name="oname" value="java"></property>
</bean>

测试类:【注意这里的context.close,原本用的ApplicationContext是没有close()这个方法,所以这里要用ClassPathXmlApplicationContext】

@Test
public void test3() {
    //1、先加载配置文件xml
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean_5.xml");

    //获取创建的配置对象
    Order order = context.getBean("order", Order.class);
    System.out.println("第四步,获取bean对象");
    System.out.println(order);
    context.close();
}

输出结果为:

bean 的后置处理器,bean 生命周期有七步  

(1)通过构造器创建 bean 实例(无参数构造) 

(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法) 

(3)把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization 【新增的第一步】

(4)调用 bean 的初始化的方法(需要进行配置初始化的方法) 

(5)把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization 【新增的第二步】

(6)bean 可以使用了(对象获取到了) 

(7)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)

基于上一个演示新增一个类演示生命周期的七步:

 (1)创建类,实现接口 BeanPostProcessor,创建后置处理器

public class MyBeanPost implements BeanPostProcessor {
    @Override
    public java.lang.Object postProcessBeforeInitialization(java.lang.Object bean,     java.lang.String beanName) throws org.springframework.beans.BeansException {
    System.out.println("在初始化之前执行方法");
    return bean;
    }
    @Override
    public java.lang.Object postProcessAfterInitialization(java.lang.Object bean, java.lang.String beanName) throws org.springframework.beans.BeansException {
    System.out.println("在初始化之后执行方法");
    return bean;
    }
}

 (2)配置后置处理器

<bean id="mybeanpost" class="spring_test.bean.MyBeanPost"></bean>

 (3)再次执行之前生命周期写的测试类(上面所写的测试类),输出的结果为:

 

IOC 操作 Bean 管理(基于注解方式)

1、什么是注解 

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

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

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

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

(1)@Component 

(2)@Service 

(3)@Controller 

(4)@Repository

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

基于注解方式实现对象创建

第一步:导入jar包

第二步:引入名称空间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">

第三步:设置context:component-scan标签进行包的扫描

<context:component-scan base-package="spring_test.bean"></context:component-scan>

 4、在类中添加注解

@Component(value = "student") //这里的value相当于 bean标签的id,可以省略不写,默认为类名称首字母该小写
public class Student {
    public void say(){
    System.out.println("我是一个坏学生");
    }
}

添加测试类看效果:

@Test
public void testzhujie() {
    //1、先加载配置文件xml
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean_6.xml");
    //获取创建的配置对象
    Student student = context.getBean("student", Student.class);
    student.say();
}

一些需要看懂的注解操作

第一个操作:

<context:component-scan base-package="spring_test" use-default-filters="false">
    <context:include-filter type="annotation"expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

解释说明:这里的【use-default-filters="false"】是指不扫描包下的所有类,需要自定义

下面的 <context:include-filter type="annotation expression="org.springframework.stereotype.Controller"/>是指只扫描包中含注解@Controller的类

第二个操作:

<context:component-scan base-package="spring_test">
    <context:exclude-filter type="annotation"expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

解释说明:这里是指不扫描包中含有@Controller注解的类

基于注解方式实现属性注入

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

         @Qualifier:根据名称进行注入 这个@Qualifier 注解的使用,和上面@Autowired 一起使用

第一步 把 service 和 dao 对象创建,在 service 和 dao 类添加创建对象注解 

第二步 在 service 注入 dao 对象,在 service 类添加 dao 类型属性,在属性上面使用注解

演示:

BookServiceImpl类:

【说明这里的@Qualifier的使用:因BookDao接口可能会有多个实现类,可以通过value值指明哪一个实现类(默认为类名首字母该小写)】

@Service
public class BookServiceImpl implements BookService{
    @Autowired
    @Qualifier(value = "bookDaoImpl")
    private BookDao bookDao;

    @Override
    public void add1() {
        System.out.println("service add.....");
        bookDao.add2();
        System.out.println(bookDao);
    }
}

 

BookDaoImpl类:

@Component
public class BookDaoImpl implements BookDao{
    public void add2() {
        System.out.println("dao add ....");
    }
}

xml的配置开启注解的扫描:【需要引入名称空间context】

<context:component-scan base-package="spring_test.dao,spring_test.service"></context:component-scan>

(2)@Resource:可以根据类型注入,可以根据名称注入(相当于@Autowired和@Qualifier的合体)

(3) @Value:注入普通类型属性

@Service
public class BookServiceImpl implements BookService{

    @Value(value = "abc")
    private String name;
    
    @Autowired
    @Qualifier(value = "bookDaoImpl")
    private BookDao bookDao;

    @Override
    public void add1() {
        System.out.println("service add....." + name);
        bookDao.add2();
        System.out.println(bookDao);
    }
}

AOP

Aop概念

1、什么是 AOP 

(1)面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得 业务逻辑各部分之间的耦合度降低,

         提高程序的可重用性,同时提高了开发的效率。

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

(3)使用登录例子说明 AOP

Aop底层原理

1、AOP 底层使用动态代理 

有两种情况动态代理 

第一种 有接口情况,使用 JDK 动态代理 

⚫ 创建接口实现类代理对象,增强类的方法

第二种 没有接口情况,使用 CGLIB 动态代理 

⚫ 创建子类的代理对象,增强类的方法

AOP-底层原理(JDK动态代理实现)

1、使用 JDK 动态代理,使用 Proxy 类里面的方法创建代理对象

(1)调用 newProxyInstance 方法

这个方法里有三个参数:

  • 第一参数,类加载器 

  • 第二参数,增强方法所在的类,这个类实现的接口,支持多个接口 

  • 第三参数,实现这个接口 InvocationHandler,创建代理对象,写增强的部分

2、编写 JDK 动态代理代码

(1)创建接口,定义方法

public interface BookDao {
    public int add(int a,int b);
    public String update(String name);
}

(2)创建接口实现类,实现方法

public class BookDaoImpl implements BookDao{
    @Override
    public int add(int a, int b) {
        return a+b;
    }

    @Override
    public String update(String name) {
        return name;
    }
}

(3)使用 Proxy 类创建接口代理对象

public class JDKProxy {
    public static void main(String[] args) {
        Class[] bookdao = {BookDao.class};
        BookDaoImpl bookDaoImpl = new BookDaoImpl();
        //这里需要用到转型,转成你需要增强的类所在的接口
        BookDao dao = (BookDao) Proxy.newProxyInstance(BookDaoImpl.class.getClassLoader(),         bookdao, new BookProxy(bookDaoImpl));
        int res = dao.add(1, 2);
        System.out.println("result:"+res);
        }
    }

    class BookProxy implements InvocationHandler {
        private Object obj;

        //通过有参构造器传入所学要增强的方法所在的类
        public BookProxy(Object obj) {
            this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //执行方法之前
        System.out.println("方法名为:" + method.getName() + " 传递的参数:" +     Arrays.toString(args));

        //增强方法
        Object result = method.invoke(obj, args);

        //执行方法之后
        System.out.println("执行方法之后" + obj);
        return result;
    }
}

 

AOP(术语)

1、连接点:类里面哪些方法可以被增强,这些方法称为连接点

2、切入点:实际被真正增强的方法,称为切入点

3、通知(增强):

    (1)实际增强的逻辑部分称为通知

    (2)通知有多种类型

  •         前置通知

  •         后置通知

  •         环绕通知

  •         异常通知

  •         最终通知

4、切面:是一种动作,把通知应用到切入点过程

AOP操作(准备工作)

1、Spring 框架一般都是基于 AspectJ 实现 AOP 操作 

(1)AspectJ 不是 Spring 组成部分,独立 AOP 框架,一般把 AspectJ 和 Spirng 框架一起使 用,进行 AOP 操作 

2、基于 AspectJ 实现 AOP 操作 

(1)基于 xml 配置文件实现 

(2)基于注解方式实现(使用) 

3、在项目工程里面引入 AOP 相关依赖(即导入jar包)

4、切入点表达式 

(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强 

(2)语法结构: execution([权限修饰符] [返回类型] [类全路径] [方法名称]([参数列表]) ) 

举例 1:对 com.atguigu.dao.BookDao 类里面的 add 进行增强 execution(* com.atguigu.dao.BookDao.add(..)) 

举例 2:对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强 execution(* com.atguigu.dao.BookDao.* (..))

举例 3:对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强 execution(* com.atguigu.dao.*.* (..))

AOP 操作(AspectJ 注解)

1、创建类,在类里面定义方法 【这个类是被增强的类,目的就是要增强里面的方法】

@Component
public class User {
    public void add(){
        System.out.println("add....");
    }
}

2、 在 spring 配置文件中,开启注解扫描【这里引入两个名称空间,分别是:context、aop】

<context:component-scan base-package="spring_test.bean2"></context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

3、创建增强类(编写增强逻辑)

@Component
@Aspect //创建代理对象
public class UserProxy {
    //前置通知
    @Before(value="execution(* spring_test.bean2.User.add(..))")     //切入的表达式:【[权限] [全类名].所要增强的方法(形参列表)】
    public void before(){
        System.out.println("before...");
    }

    //最终通知
    @After(value="execution(* spring_test.bean2.User.add(..))")
    public void after(){
        System.out.println("after....");
    }

    //后置通知(返回通知)
    @AfterReturning("execution(* spring_test.bean2.User.add(..))")
    public void afterReturnning(){
        System.out.println("afterReturnning...");
    }

    //异常通知
    @AfterThrowing("execution(* spring_test.bean2.User.add(..))")
    public void exception(){
        System.out.println("afterReturnning...");
    }

    //环绕通知
    @Around(value="execution(* spring_test.bean2.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕之前...");
        proceedingJoinPoint.proceed();
        System.out.println("环绕之后...");
    }
}

4、创建测试类

@Test
public void testanno() {
    //1、先加载配置文件xml
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");

    //获取创建的配置对象
    User user = context.getBean("user", User.class);
    user.add();
}

输出结果为:

细节点:

1、  对相同的切入点抽取
(2)在类中新建一个方法并加上注解@Pointcut(value="切入点表达式")
(2)所要使用的通知vlaue="方法名"
@Pointcut(value = "execution(* spring_test.bean2.User.add(..))")
    public void demo(){}
    
    //前置通知
    @Before(value = "demo()")
    public void before(){
        System.out.println("before...");
}

2、 有多个增强类多同一个方法进行增强,设置增强类优先级

做法如下:

    在增强类上面添加注解 @Order(数字类型值),数字类型值越小优先级越高

 

JdbcTemplate实现的jdbc的操作 

1、什么是 JdbcTemplate 

(1)Spring 框架对 JDBC 进行封装,使用 JdbcTemplate 方便实现对数据库操作

2、准备工作

(1)引入相关 jar 包

 

(2)在 spring 配置文件配置数据库连接池 并且  配置 JdbcTemplate 对象注入 DataSource 并且 进行包的扫描 

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
    <property name="url" value="jdbc:mysql:///user_db?characterEncoding=UTF-8"></property>
    <property name="username" value="数据库用户名"></property>
    <property name="password" value="数据库密码"></property>
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    </bean>
<!--引入JadbcTemplate类-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"></property>
</bean>

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

对数据库进行添加操作

1、创建实现类【这里以Book作为例子】

public class Book {
    private String bname;
    private int id;
    private String author;
   //【setter、getter方法,有参空参构造器,toString方法 省略】
}

 

2、编写 service 和 dao 
(1)在 dao 进行数据库添加操作 
(2)调用 JdbcTemplate 对象里面 update 方法实现添加操作
service类:【注意与以前不同的是添加上了注解对对象的管理】
@Service
public class BookService {
    @Autowired //注入属性
    private BookDao bookDao;

    public void addBook(Book book){
        bookDao.addbook(book);
    }
}

BookDao接口:

public interface BookDao {
    public void addbook(Book book);
}

BookDaoImpl实现类:

@Repository
public class BookDaoImpl implements BookDao {
    @Autowired //注入jdbcTemplate属性
    private JdbcTemplate jdbcTemplate;

    @Override
    public void addbook(Book book) {
        String sql = "insert into t_book values(?,?,?)";
        jdbcTemplate.update(sql,book.getBname(),book.getId(),book.getAuthor());
    }
}

测试类:

@Test
public void test_1(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean_jdbc.xml");
    BookService bookService = applicationContext.getBean("bookService", BookService.class);
    Book book = new Book("java",1,"鱼皮");
    bookService.addBook(book);
}

对数据库进行修改操作

同样用示例代码进行分析:

在上面的service中添加上以下代码

//修改操作
public void updateBook(Book book){
    bookDao.updateBook(book);
}

 BookDao接口:

public void updateBook(Book book);

BookDaoImpl实现类:

@Override
public void updateBook(Book book) 
    String sql = "update t_book set bname = ?,author = ? where id = ?";
    jdbcTemplate.update(sql,book.getBname(),book.getAuthor(),book.getId());
}

测试类:

@Test
public void test_update(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean_jdbc.xml");
    BookService bookService = applicationContext.getBean("bookService", BookService.class);
    Book book = new Book("javauper", 1, "尚硅谷");
    bookService.updateBook(book);
}

删除操作跟修改操作类似,只是将sql中的语句改为delete,同样jdebcTemplate.update()进行根据id删除

对数据库进行查询操作(查询返回某个值)

service类:

//查询返回某个值
public int selectCount(){
    return bookDao.selectCount();
}

 BookDao接口:

public int selectCount();

BookDaoImpl实现类:

@Override
public int selectCount() {
    String sql = "select count(*) from t_book";
    Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
    return count;
}

测试类:

@Test
public void test_selectCount(){
    ApplicationContext applicationContext = new     ClassPathXmlApplicationContext("bean_jdbc.xml");
    BookService bookService = applicationContext.getBean("bookService", BookService.class);
    System.out.println(bookService.selectCount());
}

一个需要注意的点:

这个方法有两个参数:

第一个参数:sql语句

第二个参数:返回类型包装类.Class

对数据库进行查询操作(查询返回对象)

service类:

//查询返回对象
public Book queryForOne(int id){
    return bookDao.queryForOne(id);
}

 BookDao接口:

public Book queryForOne(int id);

BookDaoImpl实现类:

@Override
public Book queryForOne(int id) {
    String sql = "select * from t_book where id = ?";
    Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book>(Book.class), id);
    return book;
}

测试类:

@Test
public void test_queryForOne(){
    ApplicationContext applicationContext = new     ClassPathXmlApplicationContext("bean_jdbc.xml");
    BookService bookService = applicationContext.getBean("bookService", BookService.class);
    System.out.println(bookService.queryForOne(1));
}

一个需要注意的点:

这个方法有三个参数:

第一个参数:sql

第二个参数: RowMapper 是接口,针对返回不同类型数据,使用这个接口里面实现类完成数据封装【实现类为:BeanPropertyRowMapper<>()】

第三个参数:形参列表

对数据库进行查询操作(查询返回列表) 

service类:

//查询返回集合
public List<Book> queryForList(){
    return bookDao.queryForList();
}

BookDao接口:

public List<Book> queryForList();

BookDaoImpl实现类:

@Override
public List<Book> queryForList() {
    String sql = "select * from t_book";
    List<Book> bookList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Book>(Book.class));
    return bookList;
}

测试类:

@Test
public void test_queryForList(){
    ApplicationContext applicationContext = new     ClassPathXmlApplicationContext("bean_jdbc.xml");
    BookService bookService = applicationContext.getBean("bookService", BookService.class);
    System.out.println(bookService.queryForList());
}

对数据库进行批量添加操作

service类:

//实现批量添加操作
public void addmore(List<Object[]> obj){
    bookDao.addmore(obj);
}

 BookDao接口:

public void addmore(List<Object[]> obj);

BookDaoImpl实现类:

@Override
public void addmore(List<Object[]> obj) {
    String sql = "insert into t_book values(?,?,?)";
    jdbcTemplate.batchUpdate(sql, obj);
}

测试类:

@Test
public void test_addmore(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean_jdbc.xml");
    BookService bookService = applicationContext.getBean("bookService", BookService.class);
    List<Object[]> arg = new ArrayList<>();
    Object[] o1 = {"python",3,"文琪"};
    Object[] o2 = {"php",4,"宝兰"};
    Object[] o3 = {"Go",5,"文双"};
    arg.add(o1);
    arg.add(o2);
    arg.add(o3);
    bookService.addmore(arg);
}

事务操作

事务概念

1、什么事务 
(1)事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败所有操 作都失败 
(2)典型场景:银行转账 
* lucy 转账 100 元 给 mary 
* lucy 少 100,mary 多 100 
2、事务四个特性(ACID) 
(1)原子性 
(2)一致性 
(3)隔离性 
(4)持久性

搭建事务操作环境(以实际案例说明)

以转账为例:lucy给mary转账100元

1、创建数据库表,添加记录

2、 创建 service,搭建 dao,完成对象创建和注入关系【这里是之前spring管理jdbc操作的内容】

 UserDao类:

public interface UserDao {
    //加钱的方法
    public void addMoney();

    //减钱的方法
    public void reduceMoney();
}

UserDaoImpl类:

@Repository
public class UserDaoImpl implements UserDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void addMoney() {
        String sql = "update t_account set money=money+? where username=?";
        jdbcTemplate.update(sql,100,"mary");
    }

    @Override
    public void reduceMoney() {
        String sql = "update t_account set money=money-? where username=?";
        jdbcTemplate.update(sql,100,"lucy");
    }
}

UserService类:

@Service
public class UserService {
    @Autowired
    private UserDao userDao;

    public void accountText(){
        userDao.reduceMoney();
        userDao.addMoney();
    }
}

测试类:

@Test
public void test_txdemo(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
    UserService userService = applicationContext.getBean("userService", UserService.class);
    userService.accountText();
}

引入问题:

在lucy转钱给mary的过程中出现异常,这会导致lucy的钱少了100,mary却没有增加100。

原本的做法是在service类中写事务的管理,提交或者回滚,现在我们用spring框架来实现管理。

事务操作(Spring 事务管理介绍)

1、事务添加到 JavaEE 三层结构里面 Service 层(业务逻辑层)

2、在 Spring 进行事务管理操作 

(1)有两种方式:编程式事务管理和声明式事务管理(使用) 

3、声明式事务管理 

(1)基于注解方式(使用) 

(2)基于 xml 配置文件方式 

4、在 Spring 进行声明式事务管理,底层使用 AOP 原理

5、Spring 事务管理 API 

提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类

事务操作(注解声明式事务管理)

具体的操作如下:
1、在spring配置文件事务管理器并在其注入数据源
<!--创建事务管理器-->
<bean name="TransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!--注入数据源-->
    <!--注意这里ref的dataSource是德鲁伊数据库配置的dataSource-->
    <property name="dataSource" ref="dataSource"></property>
</bean>

2、在 spring 配置文件,开启事务注解 

(1)在 spring 配置文件引入名称空间 tx【跟之前引入名称空间的操作一样】

(2)开启事务注解

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

3、在 service 类上面(或者 service 类里面方法上面)添加事务注解 

(1)@Transactional,这个注解添加到类上面,也可以添加方法上面 

(2)如果把这个注解添加类上面,这个类里面所有的方法都添加事务 

(3)如果把这个注解添加方法上面,为这个方法添加事务

案例演示:【模拟异常】

@Service
@Transactional
public class UserService {
    @Autowired
    private UserDao userDao;

    public void accountText(){

        userDao.reduceMoney();

        int i = 10/0;  //模拟异常

        userDao.addMoney();
    }
}

事务操作(声明式事务管理参数配置)

1、在 service 类上面添加注解@Transactional,在这个注解里面可以配置事务相关参数

 

2、propagation:事务传播行为

(1)当一个事务方法被另外一个事务方法调用时候,这个事务方法如何进行

 

3、ioslation:事务隔离级别  

(1)事务有特性成为隔离性,多事务操作之间不会产生影响。不考虑隔离性产生很多问题 

(2)有三个读问题:脏读、不可重复读、虚(幻)读

(3)脏读:一个未提交事务读取到另一个未提交事务的数据

(4)不可重复读:一个未提交事务读取到另一提交事务修改数据

(5)虚读:一个未提交事务读取到另一提交事务添加数据

(6)解决:通过设置事务隔离级别,解决读问题

 

设置隔离级别和事务传播的例子:

@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
public class UserService {

 

4、timeout:超时时间 
(1)事务需要在一定时间内进行提交,如果不提交进行回滚 
(2)默认值是 -1 ,设置时间以秒单位进行计算 
5、readOnly:是否只读 
(1)读:查询操作,写:添加修改删除操作 
(2)readOnly 默认值 false,表示可以查询,可以添加修改删除操作 
(3)设置 readOnly 值是 true,设置成 true 之后,只能查询
6、rollbackFor:回滚 
(1)设置出现哪些异常进行事务回滚 
7、noRollbackFor:不回滚 
(1)设置出现哪些异常不进行事务回滚

事务操作(完全注解声明式事务管理)

1、创建配置类,使用配置类替代 xml 配置文件

@Configuration //配置类
@ComponentScan(basePackages = "spring_txdeom") //开启包扫描
@EnableTransactionManagement //开启事务管理
public class TxConfig {
    //创建连接池
    @Bean
    public DataSource getDataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl("jdbc:mysql:///user_db?characterEncoding=UTF-8");
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUsername("root");
        dataSource.setPassword("Root");
        return dataSource;
    }

    //创建jdbcTemplate对象
    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource){
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        //注入dataSoruce
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

    //创建事务管理器
    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource     dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new     DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }
}

尾声

第一次写博客,总结最近在学的spring框架,跟着视频过了一遍,里面还有些spring5的新功能还没看完,但里面涉及到springboot框架,maven,springmvc,那所以把这些学完后再回来看。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值