Spring5 框架
Spring5 框架
一、Spring概述
- Spring是轻量级的开源的JavaEE框架。
- Spring可以解决企业应用开发的复杂性。
- Spring有两个核心部分:
IOC
和AOP
。- IOC:控制反转,把创建对象过程交给Spring进行管理。
- AOP:面向切面编程,不修改源代码的情况下进行功能增强。
- 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配置文件中配置对象创建,配置属性注入
<bean id ="book" class="com.atguigu.spring5.Book"></bean><bean id ="book" class="com.atguigu.spring5.Book"> <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>
- 测试
@Testpublic 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>
- 属性值包含特殊符号
<property name = "属性名"><value> </value></property>
-
注入属性-外部Bean
- 创建两个类service类和dao类
<bean id="userService" class="com.atguigu.spring5.service.UserService"> <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{ @Override public void update() { System.out.println("dao update...."); }}public class Test_02 { @Test public 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; } @Override public 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 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>
//测试@Test public 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> <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> <property name="list"> <list> <value>张三</value> <value>李四</value> <value>王麻子</value> </list> </property> <property name="maps"> <map> <entry key="JAVA" value="java"></entry> <entry key="PHP" value="php"></entry> </map> </property> <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; } @Override public 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> { @Override public Stu getObject() throws Exception { Stu stu = new Stu(); stu.setCourses(new String[]{"java","spring5"}); return stu; } @Override public Class<?> getObjectType() { return null; } @Override public boolean isSingleton() { return false; }}
<bean id="mybean" class="com.atguigu.spring5.bean.MyBean"></bean>
-
Bean的作用域
- 在spring里面,可以设置bean实例是单实例还是多实例(使用scope:singleton、prototype、request、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 id="emp" class="com.atguigu.spring5.autowire.Emp" antuwire="byName><bean id="dept" class="com.atguigu.spring5.autowire.Dept"></bean>
-
基于注解方式
-
什么是注解?注解是代码特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值…);注解可以作用在类、方法、属性上面。使用注解的目的:简化xml配置。
-
spring针对Bean管理中创建对象提供注解
- @Component
- @Service
- @controller
- @Repository
以上四个注解功能都是一样的,都可以用来创建bean实例。
<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 base-package="com.atguigu.spring5.dao, com.atguigu.spring5.service"></context:component-scan></beans>
//UserService类//在注解里面value属性值可以不写,默认值是类名称,首字母小写@Component(value="userService") //相当于public class UserService { public void add(){ System.out.println("service add..."); }}
//测试类public class TestDemo { @Test public 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(){ //加载配置类 AnnotationConfigApplicationContext ApplicationContext 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{ @Override public 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; } @Override public 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@Aspectpublic 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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--开启注解扫描--> <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
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property></bean>
-
创建service类,创建dao类,在service中注入到,dao中注入jdbcTemplate
service类
@Servicepublic class BookService { //注入bookdao @Autowired private BookDao bookDao;}
BookDao接口
public interface BookDao {}
BookDaoImple类实现BookDao
@Repositorypublic class BookDaoImpl implements BookDao{ //注入jdbcTemplate @Autowired private 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> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <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; } @Override public String toString() { return "Book{" + "id=" + id + ", bookname='" + bookname + '\'' + ", author='" + author + '\'' + ", publish='" + publish + '\'' + ", isbn='" + isbn + '\'' + ", price=" + price + ", bookresume='" + bookresume + '\'' + ", publishdate='" + publishdate + '\'' + '}'; }}
-
编写service和dao
BookService最终实现
@Servicepublic class BookService { //注入bookdao @Autowired private 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实现类
@Repositorypublic class BookDaoImpl implements BookDao{ //注入jdbcTemplate @Autowired private JdbcTemplate jdbcTemplate; //添加 @Override public 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); } @Override public 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"; } //修改 @Override public void updateBook() { String sql = "update books set bookname = ? where id = ?"; int update = jdbcTemplate.update(sql, "神雕侠侣", 9); System.out.println("总共"+update+"受影响"); } //删除 @Override public void deleteBook(int id) { String sql = "delete from books where id = ?"; int update = jdbcTemplate.update(sql, 9); System.out.println("共删除"+update+"行记录"); } //查询表记录数 @Override public void findCount() { String sql = "select count(*) from books"; Integer count = jdbcTemplate.queryForObject(sql, Integer.class); System.out.println("books表中共有"+count+"条记录"); } //查询书本详情 @Override public 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集合 @Override public 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 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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
开启事务注解
<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声明式事务管理
第一步 配置事务管理器
第二步 配置通知
第三步 配置切入点和切面
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <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 { //创建数据库连接池 @Bean public 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"); //url dataSource.setUsername("root"); //用户名 dataSource.setPassword("root"); //密码 return dataSource; } //创建jdbcTemplate对象 @Bean public JdbcTemplate getJdbcTemplate(DataSource dataSource){ //到ioc容器中根据类型找到dataSource JdbcTemplate jdbcTemplate = new JdbcTemplate(); //注入dataSource jdbcTemplate.setDataSource(dataSource); return jdbcTemplate; } //创建事务管理器 @Bean public 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 { @Test public void TestAccount(){ ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml"); UserService userService = context.getBean("userService", UserService.class); userService.BankTransfer1("1","2",500); } @Test public 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;@Repositorypublic class UserDaoImpl implements UserDao { @Autowired private JdbcTemplate jdbcTemplate; @Override public void reduceMoney(String id1, int money) { String sql = "update account set money = money - ? where id = ?"; jdbcTemplate.update(sql,money,id1); } @Override public 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 { @Test public 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
tereotype.Repository;
@Repositorypublic class UserDaoImpl implements UserDao { @Autowired private JdbcTemplate jdbcTemplate; @Override public void reduceMoney(String id1, int money) { String sql = "update account set money = money - ? where id = ?"; jdbcTemplate.update(sql,money,id1); } @Override public void addMoney(String id2, int money) { String sql = "update account set money = money + ? where id = ?"; jdbcTemplate.update(sql,money,id2); }}```测试类```javaimport 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 { @Test public void TestAccount2(){ ApplicationContext context = new AnnotationConfigApplicationContext(TxConfig.class); UserService userService = context.getBean("userService", UserService.class); userService.BankTransfer1("1","2",500); }}```运行结果:[外链图片转存中...(img-SxdR1Tsj-1651586731623)]
六、Spring5 新特性
-
整个Spring5框架基于Java8,运行时兼容JDK9,许多不建议使用的类和方法在代码库中删除
-
Spring5框架核心容器支持@Nullable注解
- 可以使用在方法上面,属性上面,参数上面,表示可以为空
-
支持函数式风格GenericApplicationContext
-
Spring5支持整合JUnit5
-
SpringWebFlux