Spring5 框架

一、Spring概述

  1. Spring是轻量级的开源的JavaEE框架。
  2. Spring可以解决企业应用开发的复杂性。
  3. Spring有两个核心部分:IOCAOP
    • IOC:控制反转,把创建对象过程交给Spring进行管理。
    • AOP:面向切面编程,不修改源代码的情况下进行功能增强。
  4. Spring特点
    • 方面解耦,简化开发
    • AOP编程支持
    • 方便程序的测试
    • 可以方便和其他框架进行整合
    • 方便进行事务操作
    • 降低API开发难度

二、IOC容器

1、IOC的概述

  • 什么是IOC:控制反转,把对象创建和对象之间的调用过程交给Spring进行管理。
  • 使用IOC的目的:为了降低耦合度。

2、IOC底层原理

  • xml解析、工厂模式、反射


3、IOC接口(BeanFactory)

  • IOC思想基于IOC容器完成,IOC容器底层就是对象工厂。
  • Spring提供IOC容器实现的两种方式(两个接口)
    • BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用
    • ApplicationContext:接口的子接口,提供更多更强大的功能,一般由开发人员进行使用
    • 区别:BeanFactory在加载配置文件时不会创建对象,在获取对象(使用)才去创建对象;ApplicationContext在加载配置文件时就会把配置文件中的对象进行创建。
  • BeanFactory接口主要实现类
    • FileSystemXmlApplicationContext:配置文件需要用系统路径(绝对路径
    • ClassPathXmlApplicationContext:配置文件使用相对路径

4、IOC操作:Bean管理(基于xml方式基于注解方式

  • 什么是Bean管理?

    • Spring创建对象
    • Spring注入属性
  • Bean管理操作有两种方式

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

    • 创建对象

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

      <!--配置文件创建对象-->
      <bean id ="user" class="com.atguigu.spring5.User"></bean>
      

      bean标签中有很多属性,常用的属性有:id(唯一标识);class(类全路径或包类路径);

      创建对象时,默认也是执行无参构造方法

    • 注入属性

      • DI:依赖注入,就是注入属性。DI是IOC的一种具体实现注入属性必须在创建完对象的基础上
    • 两种注入方式:set方法有参构造方法

      • 第一种:set方法注入

        • 创建类,定义属性和对应的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;}
        }
        
        • 在Spring配置文件中配置对象创建,配置属性注入
        <!--1、配置文件创建对象-->
        <bean id ="book" class="com.atguigu.spring5.Book"></bean><!--2、set方法注入属性-->
        <bean id ="book" class="com.atguigu.spring5.Book"><!--使用property完成属性注入name:类里面属性名称value:对应属性值--><property name="bname" value="易筋经"></property><property name="bauthor" value="达摩老祖"></property>
        </bean>
        
      • 第二种:基于有参构造方法注入

        • 创建类,定义属性,创建属性对应有参构造方法

        • public class Orders{private String oname;private String address;public Orders(String oname, String address){this.oname = oname;this.address = address;}public void orderTest(){System.out.println(oname+"::"+address)}
          }
          
        • 在Spring配置文件中进行配置

        <!--有参构造方法注入属性-->
        <bean id="oders" class="com.atguigu.spring.Orders"><constructor-arg name="oname" value="电脑"></constructor-arg><constructor-arg name="address" value="China"></constructor-arg>
        </bean>
        
        • 测试
        @Test
        public void testOrders(){//1、加载spring配置文件ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");//2、获取配置创建的对象Orders orders = context.getBean("orders",Orders.class);System.out.println(orders);orders.orderest();
        }
        
    • xml注入其他类型属性

      • 字面量:是用于源代码中一个固定值的表示法

        • null值
        <property name="属性名"><null/>
        </property>
        
        • 属性值包含特殊符号
        <!--第一种:使用转义符号--><!--第二种:把带特殊符号内容写到CDATA-->
        <property name = "属性名"><value>  <![CDATA[带特殊符号的内容]]>    </value>
        </property>
        
      • 注入属性-外部Bean

        • 创建两个类service类和dao类
        <!--service和dao对象创建--><bean id="userService" class="com.atguigu.spring5.service.UserService"><!--service中注入userDaoname:类中属性名称ref:创建userDao对象bean标签id值--><property name="userDao" ref="userDaoImpl"></property></bean><bean id="userDaoImpl" class="com.atguigu.spring5.dao.UserDaoImpl"></bean>
        
        • 在service中调用dao里面的方法
        public class UserService {//创建UserDao类型属性,生成set方法private UserDao userDao;public void setUserDao(UserDao userDao) {this.userDao = userDao;}public void add(){System.out.println("service add.....");userDao.update();}
        }public class UserDaoImpl implements UserDao{@Overridepublic void update() {System.out.println("dao update....");}
        }public class Test_02 {@Testpublic void test(){//使用ApplicationContext加载配置文件ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");//创建service对象UserService userService = context.getBean("userService", UserService.class);//调用User中的方法userService.add();}
        }
        
      • 注入属性-内部Bean和级联赋值

        • 内部Bean
        //部门类
        public class Dept {private String dname;public void setDname(String dname) {this.dname = dname;}@Overridepublic String toString() {return "Dept{" +"dname='" + dname + '\'' +'}';}
        }//员工类
        public class Emp {private String ename;private String gender;private Dept dept;          //员工所属部门public void setEname(String ename) {this.ename = ename;}public void setGender(String gender) {this.gender = gender;}public void setDept(Dept dept) {this.dept = dept;}
        }
        
        <!--配置文件-->
        <!--内部Bean-->
        <bean id="emp" class="com.atguigu.spring5.Bean.Emp"><property name="ename" value="张曼玉"></property><property name="gender" value="nv"></property><!--设置对象属性--><property name="dept"><bean id="dept" class="com.atguigu.spring5.Bean.Dept"><property name="dname" value="演艺部"></property></bean></property>
        </bean>
        
        //测试
        @Testpublic void test2(){//使用ApplicationContext加载配置文件ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");//创建service对象Emp emp = context.getBean("emp", Emp.class);//调用User中的方法emp.print();}//输出结果
        //张曼玉 女 Dept{dname='演艺部'}
        
        • 级联赋值
        <!--级联赋值  第一种写法-->
        <bean id="emp" class="com.atguigu.spring5.Bean.Emp"><property name="ename" value="张曼玉"></property><property name="gender" value="女"></property><property name="dept" ref="dept"></property>
        </bean>
        <bean id="dept" class="com.atguigu.spring5.Bean.Dept"><property name="dname" value="演艺部"></property>
        </bean><!--级联赋值  第二种写法-->
        <bean id="emp" class="com.atguigu.spring5.Bean.Emp"><property name="ename" value="张曼玉"></property><property name="gender" value="女"></property><property name="dept" ref="dept"></property><!--注意:在使用dept.dname时,需要先通过类中的get()方法获取到dept对象,否则报错--><property name="dept.dname" value="技术部"></property></bean>
        <bean id="dept" class="com.atguigu.spring5.Bean.Dept"><property name="dname" value="演艺部"></property>
        </bean>
        
    • xml注入集合属性

      <!--集合类型属性注入--><bean id="stu" class="com.atguigu.spring5.collectiontype.Stu"><!--数组类型属性注入--><property name="courses"><array><value>java面向对象程序设计</value><value>数据库设计</value><value>Spring5</value></array></property><!--List类型属性注入--><property name="list"><list><value>张三</value><value>李四</value><value>王麻子</value></list></property><!--Map类型属性注入--><property name="maps"><map><entry key="JAVA" value="java"></entry><entry key="PHP" value="php"></entry></map></property><!--Set类型属性注入--><property name="sets"><set><value>嘿嘿</value><value>哈哈</value><value>呵呵</value></set></property></bean>
      
      //学生类
      public class Stu {private String[] courses;private List<String> list;private Map<String,String> maps;private Set<String> sets;public void setCourses(String[] courses) {this.courses = courses;}public void setList(List<String> list) {this.list = list;}public void setMaps(Map<String, String> maps) {this.maps = maps;}public void setSets(Set<String> sets) {this.sets = sets;}@Overridepublic String toString() {return "Stu{" +"courses=" + Arrays.toString(courses) +", list=" + list +", maps=" + maps +", sets=" + sets +'}';}
      }//测试
      public class Test {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");Stu stu = context.getBean("stu", Stu.class);System.out.println(stu);}
      }
      //输出结果
      //Stu{courses=[java面向对象程序设计, 数据库设计, Spring5], list=[张三, 李四, 王麻子], maps={JAVA=java, PHP=php}, sets=[嘿嘿, 哈哈, 呵呵]}
      
    • 在集合里面设置对象类型值

    • 把集合注入部分提取出来

  • Bean管理(FactoryBean)

    • Spring有两种Bean,一种普通Bean,另一种工厂bean(FactoryBean)
    • 普通Bean:配置文件中定义什么类型就返回什么类型
    • 工厂Bean:配置文件中定义类型和返回类型可以不一致
    /*
    第一步:创建类,让这个类作为工厂Bean,实现接口FactoryBean
    第二步:实现接口里面的方法,在实现的方法中定义返回的bean类型如下:在xml中配置为MyBean类,但是返回的类型是Stu
    */
    public class MyBean implements FactoryBean<Stu> {@Overridepublic Stu getObject() throws Exception {Stu stu = new Stu();stu.setCourses(new String[]{"java","spring5"});return stu;}@Overridepublic Class<?> getObjectType() {return null;}@Overridepublic boolean isSingleton() {return false;}
    }
    
    <bean id="mybean" class="com.atguigu.spring5.bean.MyBean"></bean>
    
    • Bean的作用域

      • 在spring里面,可以设置bean实例是单实例还是多实例(使用scope:singleton、prototyperequest、session)。singleton和prototype的区别:1、singleton为单实例,加载配置文件时就会创建对象。2、prototype为多实例,加载的时候并不创建对象,而是在调用getBean()方法时创建多实例对象。
      • 在spring里面,默认情况下,bean是单实例对象
      //地址相同,说明stu1和stu2是同一个实例化对象
      ApplicationContext context = new ClassPathXmlApplicationContext("spring-config2.xml");Stu stu1 = context.getBean("stu", Stu.class);Stu stu2 = context.getBean("stu", Stu.class);System.out.println(stu1);System.out.println(stu2);//输出结果
      //com.atguigu.spring5.collectiontype.Stu@1e66f1f5
      //com.atguigu.spring5.collectiontype.Stu@1e66f1f5
      
    • Bean管理的生命周期:bean从创建到销毁的过程

      • 创建bean实例——>为bean的属性设置值和对其他bean引用(set方法)——>调用bean的初始化的方法(需要进行配置)——>使用——>当容器关闭时,调用bean的销毁方法(需要进行配置)
      • 添加后置处理器后变为7步:创建bean实例——>为bean的属性设置值和对其他bean引用(set方法)——>初始化前执行的方法——>调用bean的初始化的方法(需要进行配置)——>初始化后执行的方法——>使用——>当容器关闭时,调用bean的销毁方法(需要进行配置)
    • xml自动装配(很少使用)

      • 根据指定装配规则(属性名或者属性类型),Spring自动将匹配的属性值注入
      <!--自动装配bean标签属性autowire,配置自动装配autowire属性常用两个值:byName根据属性名称注入,byType根据属性类型注入
      -->
      <bean id="emp" class="com.atguigu.spring5.autowire.Emp" antuwire="byName></bean>
      <bean id="dept" class="com.atguigu.spring5.autowire.Dept"></bean>
      
  • 基于注解方式

    • 什么是注解?注解是代码特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值…);注解可以作用在类、方法、属性上面。使用注解的目的:简化xml配置。

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

      • @Component
      • @Service
      • @controller
      • @Repository

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

      <!--基于注解方式创建对象第一步:引入依赖(spring-aop-5.2.6.RELEASE.jar)第二步:开启组件扫描第三步:创建类,在类上面添加注解
      --><?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!--开启组件扫描1、扫描多个包,使用逗号','将包名隔开2、可以使用需要扫描的包的上层目录--><context:component-scan base-package="com.atguigu.spring5.dao, com.atguigu.spring5.service"></context:component-scan>
      </beans>
      
      //UserService类
      //在注解里面value属性值可以不写,默认值是类名称,首字母小写
      @Component(value="userService")     //相当于<bean id="userService" class="...></bean>
      public class UserService {public void add(){System.out.println("service add...");}
      }
      
      //测试类
      public class TestDemo {@Testpublic void testService(){//加载配置文件ApplicationContext context =new ClassPathXmlApplicationContext("spring-config2.xml");UserService userService = context.getBean("userService", UserService.class);userService.add();System.out.println(userService);}
      }
      
    • 基于注解方式实现属性注入

      • @AutoWired:根据属性类型自动装配
      • @Qualifier:根据属性名称进行注入,和@AutoWired一起使用
      • @Resource:可以根据类型注入,也可以根据名称注入
      • @Value:注入普通类型属性
    • 完全注解开发

      • 创建配置类,替代xml配置文件
      @Configuration        //将当前类作为配置类,替代xml文件
      @ComponentScan(basePackages = "com.atguigu")     //开启组件扫描
      public class SpringConfig {}
      
      • 测试类(与之前有所不同)
      public void Test02(){//加载配置类  AnnotationConfigApplicationContextApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);//创建对象UserService userService = context.getBean("userService", UserService.class);//调用方法System.out.println(userService);userService.add();}
      

三、AOP

1、概述

  • 什么是AOP?面向切面编程,是OOP的一种延续,是软件开发的一个热点。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间耦合度降低,提高程序的可重用性,同时提高开发效率

2、底层原理

  • 动态代理

    • 有两种情况动态代理:(1)有接口情况,使用JDK动态代理(2)没有接口情况,使用CGLIB动态代理

      //JDK动态代理
      /*
      1、使用JDK动态代理,使用Proxy类里面的newProxyInstance()方法创建代理对象
      newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)    三个参数:第一个(类加载器),第二个(增强方法所在的类,该类实现的接口,支持多个接口),第三个(实现这个接口的InvocationHandler,创建代理对象,写增强的方法)
      */
      

      首先定义一个People接口

      package reflect;public interface People {public String work();
      }
      

      定义一个Teacher类,该类实现People接口

      package reflect;public class Teacher implements People{@Overridepublic String work() {System.out.println("老师教书育人...");return "教书";}}
      

      现在我们要定义一个代理类的调用处理程序,每个代理类的调用处理程序都必须实现InvocationHandler接口,代理类如下:

      package reflect;import java.lang.reflect.InvocationHandler;
      import java.lang.reflect.Method;public class WorkHandler implements InvocationHandler{//代理类中的真实对象  private Object obj;public WorkHandler() {// TODO Auto-generated constructor stub}//构造函数,给我们的真实对象赋值public WorkHandler(Object obj) {this.obj = obj;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//在真实的对象执行之前我们可以添加自己的操作System.out.println("before invoke。。。");Object invoke = method.invoke(obj, args);//在真实的对象执行之后我们可以添加自己的操作System.out.println("after invoke。。。");return invoke;}}
      

      接下来我们看下客户端类

      package reflect;import java.lang.reflect.InvocationHandler;
      import java.lang.reflect.Proxy;public class Test {public static void main(String[] args) {//要代理的真实对象People people = new Teacher();//代理对象的调用处理程序,我们将要代理的真实对象传入代理对象的调用处理的构造函数中,最终代理对象的调用处理程序会调用真实对象的方法InvocationHandler handler = new WorkHandler(people);/*** 通过Proxy类的newProxyInstance方法创建代理对象,我们来看下方法中的参数* 第一个参数:people.getClass().getClassLoader(),使用handler对象的classloader对象来加载我们的代理对象* 第二个参数:people.getClass().getInterfaces(),这里为代理类提供的接口是真实对象实现的接口,这样代理对象就能像真实对象一样调用接口中的所有方法* 第三个参数:handler,我们将代理对象关联到上面的InvocationHandler对象上*/People proxy = (People)Proxy.newProxyInstance(handler.getClass().getClassLoader(), people.getClass().getInterfaces(), handler);//System.out.println(proxy.toString());System.out.println(proxy.work());}
      }
      

      看下输出结果:

      before invoke。。。
      老师教书育人...
      after invoke。。。
      教书
      

3、AOP术语

  • Advice (增强/通知)实际增强的逻辑部分成为通知(增强);通知分为(前置通知@Before、后置通知@AfterReturning、环绕通知@Around、异常通知@AferThrowing、最终通知@After)。如果有异常,AfterReturning就不执行;AfterReturning在返回值之后执行。
  • JoinPoint (连接点) 表示允许使用增强的地方。基本每个方法的前、后或异常等都是连接点。
  • Pointcut (切入点) 表示实际增强的方法。
  • Aspect (切面) 表示扩展功能的过程。
  • Introduction( 引入) 表示向现有的类中添加新方法、新属性。
  • Target (目标对象) 表示被增强的对象。
  • Proxy (代理) 表示实现AOP的机制。
  • Weaving (织入) 表示把增强应用到目标对象的过程。

4、AOP操作

  • 切入点表达式

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

    举例1:对com.atguigu.dao.BookDao类里面的add进行增强
    execution(* int com.atguigu.dao.BookDao.add(..))举例2:对com.atguigu.dao.BookDao类里面的所有方法进行增强
    execution(* com.atguiug.dao.BookDao.*(..))举例3:对com.atguigu.dao包里面所有类,类里面所有方法进行增强
    execution(* com.atguigu.dao.*.*(..))
    
  • AspectJ注解

    //1.创建类,在类里面定义方法
    public class User {public void add(){System.out.println("add ....");}
    }
    //2、编写增强逻辑
    @Component
    @Aspect
    public class UserProxy {//前置通知@Before(value = "execution(* com.atguigu.spring5.aop.User.add(..))")   //增强add()方法public void before(){System.out.println("before ...");}//后置通知@AfterReturning(value = "execution(* com.atguigu.spring5.aop.User.add(..))")public void afterReturning(){System.out.println("afterReturning...");}//环绕通知--------需要ProceedingJoinPoint类型参数@Around(value = "execution(* com.atguigu.spring5.aop.User.add(..))")public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {//环绕之前System.out.println("环绕之前...");//被增强的方法proceedingJoinPoint.proceed();//环绕之后System.out.println("环绕之后...");}//最终通知@After(value = "execution(* com.atguigu.spring5.aop.User.add(..))")public void after(){System.out.println("after...");}//异常通知@AfterThrowing(value = "execution(* com.atguigu.spring5.aop.User.add(..))")public void afterThrowing(){System.out.println("afterThrowing...");}
    }//3、进行通知的配置
    /* 在spring配置文件中,开启注解扫描;再使用注解创建User和UserProxy对象;在增强类上面添加注解@Aspect;在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:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><!--开启注解扫描--><context:component-scan base-package="com.atguigu.spring5.aop"></context:component-scan><!--开启Aspect生成代理对象--><aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    </beans>

    测试类

    public class TestAop {public static void main(String[] args) {ApplicationContext context =new ClassPathXmlApplicationContext("spring-config.xml");User user = context.getBean("user", User.class);user.add();}
    }
    

    输出结果

    环绕之前...
    before ...
    add ....
    环绕之后...
    after...
    afterReturning...
    
  • AspectJ配置文件(使用较少)

四、JDBCTemplate

1、概念

​ spring对JDBC进行了封装,JDBCTemplate方便实现对数据库的操作。

2、准备工作

  • 引入相关jar包

    mysql-connector-java-5.1.37-bin.jar (需要与数据库版本相匹配,否则会报错)

    spring-jdbc-5.2.3.RELEASE.jar

    spring-orm-5.2.3.RELEASE.jar

    spring-tx-5.2.3.RELEASE.jar

    druid-1.2.8.jar(德鲁伊数据库连接池)

  • 在spring配置文件中配置数据库连接池

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" ><property name="driverClassName" value="com.mysql.jdbc.Driver"></property><property name="url" value="jdbc:mysql://localhost:3306/book"></property><property name="username" value="root"></property><property name="password" value="root"></property>
    </bean>
    
  • 配置jdbcTemplate对象,注入DataSource

    <!--JDBCTemplate对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><!--注入DataSource--><property name="dataSource" ref="dataSource"></property>
    </bean>
    
  • 创建service类,创建dao类,在service中注入到,dao中注入jdbcTemplate

    service类

    @Service
    public class BookService {//注入bookdao@Autowiredprivate BookDao bookDao;
    }
    

    BookDao接口

    public interface BookDao {}
    

    BookDaoImple类实现BookDao

    @Repository
    public class BookDaoImpl implements BookDao{//注入jdbcTemplate@Autowiredprivate JdbcTemplate jdbcTemplate;
    }
    

    spring相关配置

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" ><property name="driverClassName" value="com.mysql.jdbc.Driver"></property><property name="url" value="jdbc:mysql://localhost:3306/book"></property><property name="username" value="root"></property><property name="password" value="root"></property></bean><!--JDBCTemplate对象--><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><!--注入DataSource--><property name="dataSource" ref="dataSource"></property></bean>
    
  • jdbcTemplate操作数据库

    • 创建数据库中实体类

      public class Book {private int id;private String bookname;private String author;private String publish;private String isbn;private float price;private String bookresume;private String publishdate;public Book(){super();}public Book(int id, String bookname, String author, String publish, String isbn, float price, String bookresume, String publishdate) {this.id = id;this.bookname = bookname;this.author = author;this.publish = publish;this.isbn = isbn;this.price = price;this.bookresume = bookresume;this.publishdate = publishdate;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getBookname() {return bookname;}public void setBookname(String bookname) {this.bookname = bookname;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}public String getPublish() {return publish;}public void setPublish(String publish) {this.publish = publish;}public String getIsbn() {return isbn;}public void setIsbn(String isbn) {this.isbn = isbn;}public float getPrice() {return price;}public void setPrice(float price) {this.price = price;}public String getBookresume() {return bookresume;}public void setBookresume(String bookresume) {this.bookresume = bookresume;}public String getPublishdate() {return publishdate;}public void setPublishdate(String publishdate) {this.publishdate = publishdate;}@Overridepublic String toString() {return "Book{" +"id=" + id +", bookname='" + bookname + '\'' +", author='" + author + '\'' +", publish='" + publish + '\'' +", isbn='" + isbn + '\'' +", price=" + price +", bookresume='" + bookresume + '\'' +", publishdate='" + publishdate + '\'' +'}';}
      }
    • 编写service和dao

      BookService最终实现

      @Service
      public class BookService {//注入bookdao@Autowiredprivate BookDao bookDao;//添加public void addBook(Book books){bookDao.add(books);}//修改public void updateBook(){bookDao.updateBook();}//删除public void deleteBook(int id){bookDao.deleteBook(id);}//查询单个值public void findCount(){bookDao.findCount();}//查询返回一个对象类型public Book findBookDetail(int id){return bookDao.findBookDetail(id);}//查询返回一个集合public List<Book> findAllBook(){return bookDao.findAllBook();}
      }

      BookDao接口

      public interface BookDao {//添加void add(Book book);//查找void query(Book book);//修改void updateBook();//删除void deleteBook(int id);//查询表记录数void findCount();//查询某本书详情,返回该书本对象Book findBookDetail(int id);List<Book> findAllBook();
      }

      BookDaoImpl实现类

      @Repository
      public class BookDaoImpl implements BookDao{//注入jdbcTemplate@Autowiredprivate JdbcTemplate jdbcTemplate;//添加@Overridepublic void add(Book book) {int id = book.getId();String bookname = book.getBookname();String author = book.getAuthor();String isbn = book.getIsbn();String publish = book.getPublish();float price = book.getPrice();String bookresume = book.getBookresume();String publishdate = book.getPublishdate();//创建sql语句String sql = "insert into books values (?,?,?,?,?,?,?,?)";int update = jdbcTemplate.update(sql, id, bookname, author, publish,isbn, price, bookresume, publishdate);System.out.println(update);}@Overridepublic void query(Book book) {int id = book.getId();String bookname = book.getBookname();String author = book.getAuthor();String isbn = book.getIsbn();String publish = book.getPublish();float price = book.getPrice();String bookresume = book.getBookresume();String publishdate = book.getPublishdate();//创建sql语句String sql = "selct * from books";}//修改@Overridepublic void updateBook() {String sql = "update books set bookname = ? where id = ?";int update = jdbcTemplate.update(sql, "神雕侠侣", 9);System.out.println("总共"+update+"受影响");}//删除@Overridepublic void deleteBook(int id) {String sql = "delete from books where id = ?";int update = jdbcTemplate.update(sql, 9);System.out.println("共删除"+update+"行记录");}//查询表记录数@Overridepublic void findCount() {String sql = "select count(*) from books";Integer count = jdbcTemplate.queryForObject(sql, Integer.class);System.out.println("books表中共有"+count+"条记录");}//查询书本详情@Overridepublic Book findBookDetail(int id) {String sql = "select * from books where id = ?";Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book>(Book.class), id);return book;}//查询Book集合@Overridepublic List<Book> findAllBook() {String sql = "select * from books";List<Book> books = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Book>(Book.class));return books;}
      }

      测试类

      import java.util.Iterator;
      import java.util.List;public class Testjdbc {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");BookService bookService = context.getBean("bookService", BookService.class);//添加元素Book book1 = new Book(9, "九阴真经", "无名氏", "机械工业出版社","12345678", 23.6f, "作者很懒,没有简介", "1998-07");
      //        bookService.addBook(book);    //增
      //        bookService.updateBook();     //改
      //        bookService.deleteBook(9);    //删
      //        bookService.findCount();        //查    返回单个值//返回一个book对象      --Book类需要有无参构造方法,否则报错
      //        Book book2 = bookService.findBookDetail(8);
      //        System.out.println(book2);//返回List<Book>List<Book> allBook = bookService.findAllBook();Iterator<Book> iterator = allBook.iterator();while(iterator.hasNext())System.out.println(iterator.next());}
      }

      测试结果

      添加:

      修改:

      删除:

      查找:单个返回值

      查找:返回book对象

    查找:返回集合

五、事务管理

1、概念

​ 什么是事务?事务是数据库操作的最基本单元,逻辑上的一组操作,该操作要么都执行,要么不执行。

2、事务的四个特性(ACID)

  • 原子性:操作要么全部执行,要么都不执行
  • 一致性:操作前和操作后的状态保持一致(例如银行转账前和转账后的总钱数是相同的)
  • 隔离性:不同事务的操作互不影响
  • 持久性:事务提交之后的改变是永久的

3、事务操作

  • 事务通常添加到Service层

  • spring中有两种方式进行事务管理:编程式事务管理(了解)和声明式事务管理(使用)

    • 声明事务管理:基于注解方式(常用)和基于xml配置文件方式
    • 声明事务管理底层使用了AOP原理
  • 事务操作

    • 1、在spring配置文件中配置事务管理器

      <!--创建事务管理器-->
      <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!--注入数据源--><property name="dataSource" ref="dataSource"></property>
      </bean>
      
    • 配置开启事务注解

      先引入命名空间tx

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

      开启事务注解

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

      在service类上面(或者里面的方法上面)添加事务注解**@Transactional**

      如果注解添加在类上面,那么类里面的所有方法都添加事务;如果注解添加到方法上面,那么只有该方法添加事务。

      事务注解中的参数设置

      1、**propagation:**事务传播行为。多事务方法间直接进行调用,这个过程中事务是如何进行管理的。

      ​ spring定义了7种传播行为:

      传播属性 描述
      REQUIRED 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
      SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
      MANDATORY 支持当前事务,如果当前没有事务,就抛出异常。
      REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
      NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
      NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
      NESTED 支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。

      2、**isolation:**事务隔离级别

      ​ 事务有特性成为隔离性,多事务操作之间不会产生影响。不考虑隔离性产生很多问题
      ​ 有三个读问题:脏读、不可重复读、虚(幻)读

      ​ **脏读(致命问题):**一个未提交事务读取到另一个未提交事务的数据

      ​ **不可重复读:**一个未提交事务读取到另一个已提交事务的数据

      ​ **虚(幻)读:**一个未提交事务读取到另一个已提交事务添加的数据

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

      脏读 不可重复读 幻读
      READ UNCOMMITTED(读未提交)
      READ COMMITTED(读已提交)
      REPEATABLE READ(可重复读)
      SERIALIZABLE(串行化)

      3、**timeout:**超时时间

      ​ 事务需要在一定时间内进行提交,如果不提交进行回滚
      ​ 默认值是-1 ,设置时间以秒单位进行计算

      4、**readOnly:**是否只读

      ​ 读:查询操作,写:添加修改删除操作
      ​ readOnly 默认值false,表示可以查询,可以添加修改删除操作
      ​ 设置readOnly 值是true,设置成true 之后,只能查询

      5、**rollbackFor:**回滚

      ​ 设置出现哪些异常进行事务回滚

      6、**noRollbackFor:**不回滚

      ​ 设置出现哪些异常不进行事务回滚

    • xml声明式事务管理

      第一步 配置事务管理器

      第二步 配置通知

      第三步 配置切入点和切面

      <!--1、创建事务管理器--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!--注入数据源--><property name="dataSource" ref="dataSource"></property></bean><!--2、配置通知--><tx:advice id="txadvice"><!--配置事务参数--><tx:attributes><!--指定哪种规则的方法上面添加事务--><tx:method name="BankTransfer2" propagation="REQUIRED" isolation="REPEATABLE_READ"/></tx:attributes></tx:advice><!--配置切入点和切面--><aop:config><!--配置切入点--><aop:pointcut id="pointcut" expression="execution(* com.atguigu.spring5.service.UserService.*(..))"/><!--配置切面--><aop:advisor advice-ref="txadvice" pointcut-ref="pointcut"></aop:advisor></aop:config>
      
    • 完全注解实现声明式事务管理

      第一步 创建配置类,替代xml文件

      package com.atguigu.spring5.config;import com.alibaba.druid.pool.DruidDataSource;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.ComponentScan;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.jdbc.core.JdbcTemplate;
      import org.springframework.jdbc.datasource.DataSourceTransactionManager;
      import org.springframework.transaction.annotation.EnableTransactionManagement;import javax.sql.DataSource;@Configuration    //配置类
      @ComponentScan(basePackages = "com.atguigu")    //组件扫描
      @EnableTransactionManagement        //开启事务
      public class TxConfig {//创建数据库连接池@Beanpublic DruidDataSource getDruidDataSource(){DruidDataSource dataSource = new DruidDataSource();  //德鲁伊连接池dataSource.setDriverClassName("com.mysql.jdbc.Driver"); //加载驱动dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/account?characterEncoding=UTF-8");  //urldataSource.setUsername("root");  //用户名dataSource.setPassword("root");  //密码return dataSource;}//创建jdbcTemplate对象@Beanpublic JdbcTemplate getJdbcTemplate(DataSource dataSource){//到ioc容器中根据类型找到dataSourceJdbcTemplate jdbcTemplate = new JdbcTemplate();//注入dataSourcejdbcTemplate.setDataSource(dataSource);return jdbcTemplate;}//创建事务管理器@Beanpublic DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();//注入数据源transactionManager.setDataSource(dataSource);return transactionManager;}
      }
      

      service类

      import com.atguigu.spring5.config.TxConfig;
      import com.atguigu.spring5.service.UserService;
      import org.junit.Test;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.annotation.AnnotationConfigApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestDemo {@Testpublic void TestAccount(){ApplicationContext context =new ClassPathXmlApplicationContext("spring-config.xml");UserService userService = context.getBean("userService", UserService.class);userService.BankTransfer1("1","2",500);}@Testpublic void TestAccount2(){ApplicationContext context =new AnnotationConfigApplicationContext(TxConfig.class);UserService userService = context.getBean("userService", UserService.class);userService.BankTransfer1("1","2",500);}
      }

      dao接口

      package com.atguigu.spring5.dao;public interface UserDao {void reduceMoney(String id1, int money);void addMoney(String id2, int money);
      }

      dao实现类

      package com.atguigu.spring5.dao;import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.jdbc.core.JdbcTemplate;
      import org.springframework.stereotype.Repository;@Repository
      public class UserDaoImpl implements UserDao {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic void reduceMoney(String id1, int money) {String sql = "update account set money = money - ? where id = ?";jdbcTemplate.update(sql,money,id1);}@Overridepublic void addMoney(String id2, int money) {String sql = "update account set money = money + ? where id = ?";jdbcTemplate.update(sql,money,id2);}
      }

      测试类

      import com.atguigu.spring5.config.TxConfig;
      import com.atguigu.spring5.service.UserService;
      import org.junit.Test;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class TestDemo {@Testpublic void TestAccount2(){ApplicationContext context =new AnnotationConfigApplicationContext(TxConfig.class);UserService userService = context.getBean("userService", UserService.class);userService.BankTransfer1("1","2",500);}
      }

      运行结果:

六、Spring5 新特性

  • 整个Spring5框架基于Java8,运行时兼容JDK9,许多不建议使用的类和方法在代码库中删除

  • Spring5框架核心容器支持@Nullable注解

    • 可以使用在方法上面,属性上面,参数上面,表示可以为空
  • 支持函数式风格GenericApplicationContext

  • Spring5支持整合JUnit5

  • SpringWebFlux

Spring5 框架相关推荐

  1. Java总结:Spring5框架(1)

    Spring5框架(1) 一:什么是Spring? Spring框架是由于软件开发的复杂性而创建的.Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情.然而,Spring的用 ...

  2. Spring5 框架新功能(Webflux)

    目录 1.SpringWebflux 介绍 2.响应式编程(Java 实现) 3.响应式编程(Reactor 实现) 1.SpringWebflux 介绍 (1)SpringWebflux 是 Spr ...

  3. Spring5框架-IOC容器

    Spring5框架 Spring包下载快照 一.Spring简绍 1什么是Spring 1.Spring是轻量级的开源的JAVAEE框架,可以解决企业应用开发的复杂性 2.Spring有两个核心的部分 ...

  4. Java系列技术之Spring5框架-钟洪发-专题视频课程

    Java系列技术之Spring5框架-33人已学习 课程介绍         Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个 ...

  5. Spring5 框架概述 、IOC 容器

    一.Spring5 框架概述 介绍 Spring 是轻量级的开源的 JavaEE 框架 Spring 可以解决企业应用开发的复杂性 Spring 有两个核心部分:IOC 和 Aop (1)IOC:控制 ...

  6. Spring5框架(上) IOC

    Spring5框架 IOC 前言 Spring框架概述 IOC容器 底层原理 Bean管理XML方式(创建对象和set注入属性) 注入集合类型属性1 IOC操作Bean管理 Bean管理(工厂Bean ...

  7. 001 spring5框架:java类工程,IOC:实体类表示表关系,AOP,JdbcTemplate模板,事务操作,Spring5 框架新功能:日志,为空注解,函数式风格,juint,Webflux

    1. Spring5 框架(Spring5 Framework)介绍 1.1 概念 1.Spring 是轻量级的开源的 JavaEE 框架 2.Spring 可以解决企业应用开发的复杂性 3.Spri ...

  8. Spring5框架学习

    Spring5框架学习 备注:视频来源于尚硅谷 - Spring 5 框架最新版教程(idea版):https://www.bilibili.com/video/BV1Vf4y127N5 Spring ...

  9. Spring5框架 笔记总结(二)

    文章目录 1. 使用Java 的方式配置Spring 2. 代理模式 3. 动态代理 简述 4. 动态代理的使用 4.1 动态代理的使用 4.2 动态代理补充 5. Spring AOP 6. 实现a ...

最新文章

  1. 痞子衡嵌入式:常用的数据差错控制技术(2)- 奇偶校验(Parity Check)
  2. 【Oracle】Oracle常用EVENT之三
  3. Python学习笔记:list和tuple
  4. 用计算机进行资料检索工作是,用计算机进行资料检索工作是属于计算机应用中的什么...
  5. shell编程中date用法(转)
  6. compat包_使用Compat Patchers,API的稳定性既便宜又容易!
  7. 大学生免费查题公众号_诺奖作家英文作品赏析尔雅2020年答案查题公众号
  8. 学习WPF绝佳的去处……WPF教程,WPF入门教程,WPF视频教程
  9. URLDecoder用法
  10. cai计算机辅助教程,拓展:计算机辅助教学(CAI)的基本模式
  11. 马士兵java学习之路
  12. 处理效应模型stata实例_『Stata』政策处理效应PSM模型基本命令汇总
  13. 小蛋机器人app_阿尔法蛋编程APP
  14. Adobe photo shop 裁剪某个图层中图片的大小
  15. IDM(Internet Download Manager)—下载各类安装包(github代码、python包)、软件、视频、文档的神器,居家必备良药...
  16. 玩转AgiileCDN(十三)——全站加速
  17. CSS box-shadow 详解
  18. Pycharm导入scap包提示出错
  19. Keil中代码前进后退跳转快捷键修改
  20. ESP32设备驱动-SHT30温度湿度传感器驱动

热门文章

  1. python打不开xls文件,wps下用vba实现合并文件夹中所有excel文件
  2. Flask学习笔记之g对象
  3. webots和ros2笔记05-新建
  4. cmnet 和 cmwap 收费等区别
  5. 享受知识饕餮盛宴,尽在近期课程安排
  6. 除了菊纹识别,AI还有哪些奇奇怪怪的识别能力?
  7. 微信小程序java中文乱码_如何解决微信小程序显示中文无法上传或者出现乱码的问题?...
  8. Lombok的@Data注解自动重写equals
  9. EventBus3 简单使用及注意点
  10. mybatis批量入库(springboot mybatis 批量入库)