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配置文件中配置对象创建,配置属性注入
<!--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、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标签属性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 框架相关推荐
- Java总结:Spring5框架(1)
Spring5框架(1) 一:什么是Spring? Spring框架是由于软件开发的复杂性而创建的.Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情.然而,Spring的用 ...
- Spring5 框架新功能(Webflux)
目录 1.SpringWebflux 介绍 2.响应式编程(Java 实现) 3.响应式编程(Reactor 实现) 1.SpringWebflux 介绍 (1)SpringWebflux 是 Spr ...
- Spring5框架-IOC容器
Spring5框架 Spring包下载快照 一.Spring简绍 1什么是Spring 1.Spring是轻量级的开源的JAVAEE框架,可以解决企业应用开发的复杂性 2.Spring有两个核心的部分 ...
- Java系列技术之Spring5框架-钟洪发-专题视频课程
Java系列技术之Spring5框架-33人已学习 课程介绍 Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个 ...
- Spring5 框架概述 、IOC 容器
一.Spring5 框架概述 介绍 Spring 是轻量级的开源的 JavaEE 框架 Spring 可以解决企业应用开发的复杂性 Spring 有两个核心部分:IOC 和 Aop (1)IOC:控制 ...
- Spring5框架(上) IOC
Spring5框架 IOC 前言 Spring框架概述 IOC容器 底层原理 Bean管理XML方式(创建对象和set注入属性) 注入集合类型属性1 IOC操作Bean管理 Bean管理(工厂Bean ...
- 001 spring5框架:java类工程,IOC:实体类表示表关系,AOP,JdbcTemplate模板,事务操作,Spring5 框架新功能:日志,为空注解,函数式风格,juint,Webflux
1. Spring5 框架(Spring5 Framework)介绍 1.1 概念 1.Spring 是轻量级的开源的 JavaEE 框架 2.Spring 可以解决企业应用开发的复杂性 3.Spri ...
- Spring5框架学习
Spring5框架学习 备注:视频来源于尚硅谷 - Spring 5 框架最新版教程(idea版):https://www.bilibili.com/video/BV1Vf4y127N5 Spring ...
- Spring5框架 笔记总结(二)
文章目录 1. 使用Java 的方式配置Spring 2. 代理模式 3. 动态代理 简述 4. 动态代理的使用 4.1 动态代理的使用 4.2 动态代理补充 5. Spring AOP 6. 实现a ...
最新文章
- 痞子衡嵌入式:常用的数据差错控制技术(2)- 奇偶校验(Parity Check)
- 【Oracle】Oracle常用EVENT之三
- Python学习笔记:list和tuple
- 用计算机进行资料检索工作是,用计算机进行资料检索工作是属于计算机应用中的什么...
- shell编程中date用法(转)
- compat包_使用Compat Patchers,API的稳定性既便宜又容易!
- 大学生免费查题公众号_诺奖作家英文作品赏析尔雅2020年答案查题公众号
- 学习WPF绝佳的去处……WPF教程,WPF入门教程,WPF视频教程
- URLDecoder用法
- cai计算机辅助教程,拓展:计算机辅助教学(CAI)的基本模式
- 马士兵java学习之路
- 处理效应模型stata实例_『Stata』政策处理效应PSM模型基本命令汇总
- 小蛋机器人app_阿尔法蛋编程APP
- Adobe photo shop 裁剪某个图层中图片的大小
- IDM(Internet Download Manager)—下载各类安装包(github代码、python包)、软件、视频、文档的神器,居家必备良药...
- 玩转AgiileCDN(十三)——全站加速
- CSS box-shadow 详解
- Pycharm导入scap包提示出错
- Keil中代码前进后退跳转快捷键修改
- ESP32设备驱动-SHT30温度湿度传感器驱动
热门文章
- python打不开xls文件,wps下用vba实现合并文件夹中所有excel文件
- Flask学习笔记之g对象
- webots和ros2笔记05-新建
- cmnet 和 cmwap 收费等区别
- 享受知识饕餮盛宴,尽在近期课程安排
- 除了菊纹识别,AI还有哪些奇奇怪怪的识别能力?
- 微信小程序java中文乱码_如何解决微信小程序显示中文无法上传或者出现乱码的问题?...
- Lombok的@Data注解自动重写equals
- EventBus3 简单使用及注意点
- mybatis批量入库(springboot mybatis 批量入库)