//方法一:转义字符
//方法二:CDATA
<![CDATA[<北京>]]>
(3 )注入外部bean(使用引用,注入其他类的对象)
(1) 创建两个类service类和dao类
(2) 在service调用dao类的方法
(3) 在spring配置文件中进行配置
package com.caq.spring5.dao;
public interface UserDao {
public void update();
}
package com.caq.spring5.dao;
public class UserDaoImpl implements UserDao {
@Override
public void update() {
System.out.println(“dao update!!!”);
}
}
package com.caq.spring5.service;
import com.caq.spring5.User;
import com.caq.spring5.dao.UserDao;
import com.caq.spring5.dao.UserDaoImpl;
public class UserService {
// 创建UserDao类型属性,生成set方法
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add(){
System.out.println(“add service!!!”);
// 创建UserDao对象(普通的方式实现)
UserDao userDao = new UserDaoImpl();
userDao.update();
}
}
<?xml version="1.0" encoding="UTF-8"?><beans xmlns=“http://www.springframework.org/schema/beans”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=“http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd”>
再次回想上面所说,Spring就是将创建对象的操作交给IOC容器(体会到了工厂模式(中介)),通过XML解析获取要创建对象的信息中间也用到了反射,其实最后是通过反射来创建对象调用方法
(4)注入集合
-
注入数组类型属性
-
注入List集合类型属性
-
注入Map集合类型属性
-
注入集合元素是对象的集合
(1)创建类,定义数组、list、map、set类型属性,生成对应set方法
package com.caq.spring5.collectiontype;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Stu {
private String[] courses;
private List list;
private Map<String,String> maps;
private Set sets;
private List courseList;
public void setCourseList(List courseList) {
this.courseList = courseList;
}
public void setCourses(String[] courses) {
this.courses = courses;
}
public void setList(List list) {
this.list = list;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
public void setSets(Set sets) {
this.sets = sets;
}
public void test(){
System.out.println(Arrays.toString(courses));
System.out.println(list);
System.out.println(maps);
System.out.println(sets);
System.out.println(courseList);
}
}
xml代码
<?xml version="1.0" encoding="UTF-8"?><beans xmlns=“http://www.springframework.org/schema/beans”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=“http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd”>
Java
Mysql
张三
唐浩
Mysql
Redis
测试代码
package com.caq.spring5.testdemo;
import com.caq.spring5.authwire.Emp;
import com.caq.spring5.bean.Orders;
import com.caq.spring5.collectiontype.Book;
import com.caq.spring5.collectiontype.Course;
import com.caq.spring5.collectiontype.Stu;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring5Demo1 {
@Test
public void testCollection() {
ApplicationContext context = new ClassPathXmlApplicationContext(“bean1.xml”);
Stu stu = context.getBean(“stu”, Stu.class);
stu.test();
}
@Test
public void testCollection2() {
ApplicationContext context = new ClassPathXmlApplicationContext(“bean2.xml”);
Book book = context.getBean(“book”, Book.class);
Book book2 = context.getBean(“book”, Book.class);
book.test();
// System.out.println(book);
// System.out.println(book2);
}
@Test
public void test3() {
ApplicationContext context = new ClassPathXmlApplicationContext(“bean3.xml”);
Course course = context.getBean(“myBean”, Course.class);
System.out.println(course);
}
@Test
public void testBean3() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(“bean4.xml”);
Orders orders = context.getBean(“orders”, Orders.class);
System.out.println(“第四步 获取创建bean实例对象”);
System.out.println(orders);
// 手动销毁bean实例
context.close();
}
@Test
public void testBean4() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(“bean5.xml”);
Emp emp = context.getBean(“emp”, Emp.class);
System.out.println(emp);
// 手动销毁bean实例
context.close();
}
}
(5)把集合公共部分提取出来
<?xml version="1.0" encoding="UTF-8"?><beans xmlns=“http://www.springframework.org/schema/beans”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xmlns:util=“http://www.springframework.org/schema/util”
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<util:list id=“booklist”>
Curry
Kb
Jordan
</util:list>
2.4.5 FactotyBean
Spring 有两种类型bean,一种普通bean,另外一种工厂bean(FactoryBean)
(1)普通bean在配置文件中,定义bean类型就是返回类型
(2)工厂bean在配置文件中定义bean类型可以和返回类型不一样
第一步创建类,让这个类作为工厂Bean,实现接口FactoryBean
第二步实现接口里的方法,在实现方法中定义返回的bean类型
如下程序:
xm文件中定义的返回bean返回类型是Mybean
然后我实现接口后,定义返回的类型为Course类型的bean
package com.caq.spring5.factorybean;
import com.caq.spring5.collectiontype.Course;
import org.springframework.beans.factory.FactoryBean;
public class MyBean implements FactoryBean {
// 定义返回bean
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setCname(“abc”);
return course;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
2.4.6 bean作用域
(1)在spring里,设置创建Bean实例是单实例还是多实例。
(2)在spring里,默认设置创建Bean实例是单实例。
(3)如何设置单实例还是多实例。
spring配置文件bean标签里scope属性用于设置单实例还是多实例。
scope属性值:第一个,默认值,singleton,表示单实例对象;第二个值:prototype,表示多实例对象。
<?xml version="1.0" encoding="UTF-8"?><beans xmlns=“http://www.springframework.org/schema/beans”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xmlns:util=“http://www.springframework.org/schema/util”
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
因为是多实例所以是两个不同的地址
(4)singleton 与 prototype区别
第一,singleton表示单实例,prototype表示多实例。
第二,设置Scope是singleton时,加载spring配置文件时侯就会创建单实例对象;
设置Scope是prototype时,不是加载spring配置文件时侯创建对象,而是在调用getBean方法时创建多实例对象。
request,表示一次请求,每次创建对象放到request域对象中。
session,表示一次会话,每次创建对象放到session域对象中。
2.4.7 生命周期
什么是生命周期?
从对象创建到对象销毁的过程
bean生命周期
(1)通过构造器创建bean实例(无参数构造)
(2)为bean的属性设置值和对其他bean引用(调用set方法)
(3)调用bean的初始化的方法(需要进行配置)
(4)bean可以使用了(对象获取到了)
(5)当容器关闭的时候,调用bean的销毁的方法(需要进行配置销毁的方法)
bean的后置处理器,bean生命周期有七步
(1)通过构造器创建bean实例(无参数构造)
(2)为bean的属性设置值和对其他bean引用(调用set方法)
(3)把bean实例传递bean后置处理器的方法postProcessBeforeInitialization
(4)调用bean的初始化的方法(需要进行配置)
(5)把bean实例传递bean后置处理器的方法postProcessAfterInitialization
(6)bean可以使用了(对象获取到了)
(7)当容器关闭的时候,调用bean的销毁的方法(需要进行配置销毁的方法)
package com.caq.spring5.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.lang.Nullable;
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(“在初始化之前执行的方法”);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(“在初始化之后执行的方法”);
return bean;
}
}
package com.caq.spring5.bean;
public class Orders {
private String oname;
public Orders() {
System.out.println(“第一步 执行无参构造创建bean实例”);
}
public void setOname(String oname){
this.oname = oname;
System.out.println(“第二步,调用set方法设置值”);
}
public void initMethod(){
System.out.println(“第三部 执行初始化方法”);
}
public void destoryMethod(){
System.out.println(“第五步 执行销毁的方法”);
}
}
<?xml version="1.0" encoding="UTF-8"?><beans xmlns=“http://www.springframework.org/schema/beans”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xmlns:util=“http://www.springframework.org/schema/util”
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
2.4.8 自动装配
- 什么是自动装配
(1)根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入
bean标签属性autowire,配置自动装配autowire属性常用两个值:
byName根据属性名称注入,注入值bean 的id 值和类属性名称一样
byType根据属性类型注入
根据名称就按照id(注入值bean 的id 值和类属性名称一样)
类型就是class后面的
<?xml version="1.0" encoding="UTF-8"?><beans xmlns=“http://www.springframework.org/schema/beans”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xmlns:util=“http://www.springframework.org/schema/util”
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
2.5.1 什么是注解
格式:@注解名称(属性名=属性值)
使用注解:注解作用在类(方法,属性)上
使用目的:简化xml配置
2.5.2 Spring针对Bean管理中创建对象提供注解
-
@Component 普通用法
-
@Service 用于service业务逻辑层
-
@Controller 用于web层
-
@Repository 用于DAO持久层
2.5.3 基于注解方式实现对象创建例子
第一步 引入依赖
第二步 开启组件扫描
1 如果扫描多个包,多个包使用逗号隔开
2 扫描包上层目录
<context:component-scan base-package=“com.caq”></context:component-scan>
上面就是扫描整个caq包
第三步 创建类,在类上面添加创建对象注解
//在注解里面 value 属性值可以省略不写,
//默认值是类名称,首字母小写 /
/UserService – userService
//@Component(value = “userService”)@Service//@Controller@Repositorypublic class UserService {}
一些扫描细节直接粘贴笔记了
就是扫描的时候扫描那些,和不扫描那些
2.5.4 基于注解方式实现属性注入
(1)@Autowired:根据属性类型进行自动装配
第一步把service和 dao对象创建,在service和 dao类添加创建对象注解
第二步在service注入dao对象,在service类添加dao类型属性,在属性上面使用注解
(2)@Qualifier:根据名称进行注入
这个@Qualifier注解的使用,和上面@Autowired一起使用
(3)@Resource:可以根据类型注入,可以根据名称注入
(4)@Value:注入普通类型属性
2.5.5 完全注解开发
就是我不依赖xml了,我全用注解的知识
(1)创建配置类,替代 xml 配置文件
package com.caq.spring5.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration //作为配置类,代替xml配置文件@ComponentScan(basePackages = {“com.caq”})public class SpringConfig {}
(2)编写测试类
@Testpublic void testService2(){
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = context.getBean(“userService”, UserService.class);
System.out.println(userService);
userService.add();
}
com.caq.spring5.service.UserService@3eb7fc54Service
add…abc
do add…
====================================================================
(1)面向切面编程(方面),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
(2)通俗描述:不通过修改源代码方式,在主干功能里面添加新功能(符合设计模式中的开闭原则,不修改源码,但是能打开扩展功能)
(3)使用登录例子说明AOP
1、AOP 底层使用动态代理
(1)有两种情况动态代理
第一种 有接口情况,使用 JDK 动态代理
创建接口实现类代理对象,增强类的方法
第二种 没有接口情况,使用 CGLIB 动态代理
创建子类的代理对象,增强类的方法
方法有三个参数:
第一参数,类加载器
第二参数,增强方法所在的类,这个类实现的接口,支持多个接口
第三参数,实现这个接口InvocationHandler,创建代理对象,写增强的部分
3.3.1 难点解析
想要实现动态代理,需要解决的问题?
问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象
问题二:当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a
1.通过反射提供的API动态的创建一个代理类
2.首先new一个被代理类的对象,传入创建代理类对象的方法中
3.创建代理类的方法中的参数handler其实就抽象化了被代理类要执行的方法
4.handler参数是一个接口,我们创建handler接口的实现类,实例化handler接口的实现类的时候参数为被代理类对象
5.handler接口的实现类重写了handler的invoke方法,
6.invoke方法第二个参数是Method类的method对象,我们通过这个对象可以调用运行时类的方法(运行时类就是我们的加载到内存中的被代理类)
7.之后我们通过method.invoke(obj,args),第一个obj参数就是被代理类的对象,调用invoke方法时的参数(不知道invoke的可以回顾下反射)
8.这样就可以实现调用代理类对象的invoke方法时,也调用被代理类的方法
9.反射的主要特点就是体会到它的动态性,就是因为我们的代理类没有显示的给它定义出来,而是在运行的时候根据你传入的被代理类的对象是谁
10.我们动态的帮你创建的,体现了反射的动态性
package com.caq.spring5;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class JDKProxy {
public static void main(String[] args) {
// 创建接口实现类的代理对象
Class[] interfaces = {UserDao.class};
UserDaoImpl userDao = new UserDaoImpl();
UserDao dao = (UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
// int add = dao.add(1, 2);
// System.out.println(add);
String update = dao.update(“3”);
System.out.println(update);
}
}
class UserDaoProxy implements InvocationHandler{
private Object obj;
public UserDaoProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(“方法之前执行…”+method.getName()+“:传递的参数…”+ Arrays.toString(args));
Object res = method.invoke(obj, args);
System.out.println(“方法之后执行…”+obj);
return res;
}
}
public static void main(String[] args) {
// 创建接口实现类的代理对象
Class[] interfaces = {UserDao.class};
UserDaoImpl userDao = new UserDaoImpl();
UserDao dao = (UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
// int add = dao.add(1, 2);
// System.out.println(add);
String update = dao.update(“3”);
System.out.println(update);
}
}
3.4.1 连接点
类里面哪些方法可以被增强,这些方法称为连接点
3.4.2 切入点
实际被真正增强的方法,称为切入点
3.4.3 通知(增强)
(1)实际增强的逻辑部分称为通知(增强)
(2)通知有多钟类型前置通知
-
后前通知:在要增强方法前执行
-
后置通知:在要增强方法后执行
-
环绕通知:在要增强方法前后都执行
-
异常通知:增强方法发生异常后执行
-
最终通知:类似与finally,无论发生不发生异常都会执行
3.4.4 切面
是动作(过程)
(1)把通知应用到切入点过程
3.5.1 什么是AspectJ?
也是一个框架,一般和Spring一起使用,进行AOP操作
3.5.2 基于AspectJ实现AOP操作
(1)基于xml配置文件实现
(2)基于注解方式实现
3.5.3 在项目工程中引入AOP依赖
3.5.4 切入点表达式
切入点表达式作用就是知道对哪个类里面的方法进行增强
语法结构:
execution([权限修饰符] [返回类型] [类全路径] [方法名称] ([参数列表]))
举例:对com.caq.dao.BookDao类里的add进行增强
execution(* com.caq.dao.BookDao.add(…))
星号代表所有修饰符,返回值类型可以省略不写
对com.caq.dao.BookDao类里的所有方法进行增强
execution(* com.caq.dao.BookDao.*(…))
对com.caq.dao包里的所有类和方法进行增强
对execution(* com.caq.dao. * . * (…))
3.6.1 创建类,在类里面定义方法
package com.caq.spring5.aopano;
public class User {
public void add(){
System.out.println(“add…”);
}
}
3.6.2 创建增强类(编写增强逻辑)
在增强类里面,创建方法,让不同方法代表不同通知类型
package com.caq.spring5.aopano;
public class UserProxy {
public void before(){
System.out.println(“before~~~”);
}
}
3.6.3 进行通知的配置
(1)在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.caq.spring5.aopano”></context:component-scan>
aop:aspectj-autoproxy</aop:aspectj-autoproxy>
(2)使用注解创建User和UserProxy对象
其实就是在它们上面加个Compoent就行了
package com.caq.spring5.aopano;
import org.springframework.stereotype.Component;
@Component
public class User {
public void add(){
System.out.println(“add…”);
}
}
package com.caq.spring5.aopano;
import org.springframework.stereotype.Component;
@Componentpublic
class UserProxy {
public void before(){
System.out.println(“before~~~”);
}
}
(3)在增强类上添加注解@Aspect
package com.caq.spring5.aopano;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Component
@Aspect//生产代理对象
public class UserProxy {
public void before(){
System.out.println(“before~~~”);
}
}
(4)在Spring配置文件中开启生产代理对象
<?xml version="1.0" encoding="UTF-8"?><context:component-scan base-package=“com.caq.spring5.aopano”>
</context:component-scan>
aop:aspectj-autoproxy
</aop:aspectj-autoproxy>
3.7 配置不同类型的通知
package com.caq.spring5.aopano;
import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component@Aspect//生产代理对象
public class UserProxy { // beforer注解表示作为前置通知
@Before(value = “execution(* com.caq.spring5.aopano.User.add(…))”)
public void before() {
System.out.println(“before~~~”);
} //后置通知
@AfterReturning(value = “execution(* com.caq.spring5.aopano.User.add(…))”)
public void afterReturning() {
System.out.println(“AfterReturning~~~”);
} //最终通知
@After(value = “execution(* com.caq.spring5.aopano.User.add(…))”)
public void after() {
System.out.println(“after~~~”);
}// 异常通知
@AfterThrowing(value = “execution(* com.caq.spring5.aopano.User.add(…))”)
public void afterThrowing() {
System.out.println(“afterThrowing~~~”);
}// 环绕通知
@Around(value = “execution(* com.caq.spring5.aopano.User.add(…))”)
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println(“环绕之前~~~”);// 被增强的方法执行
proceedingJoinPoint.proceed();
System.out.println(“环绕之后~~~”);
}
}
环绕之前~~~
before~~~add…
环绕之后~~~
after~~~
AfterReturning~~~
3.8 公共切入点抽取
package com.caq.spring5.aopano;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Aspect//生产代理对象
@Order(3)
public class UserProxy {
//相同切入点抽取
@Pointcut(value = “execution(* com.caq.spring5.aopano.User.add(…))”)
public void pointdemo(){
}
//后置通知
@AfterReturning(value = “pointdemo()”)
public void afterReturning() {
System.out.println(“AfterReturning~~~”);
}
//最终通知
@After(value = “pointdemo()”)
public void after() {
System.out.println(“after~~~”);
}
// 异常通知
@AfterThrowing(value = “pointdemo()”)
public void afterThrowing() {
System.out.println(“afterThrowing~~~”);
}
// 环绕通知
@Around(value = “pointdemo()”)
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println(“环绕之前~~~”);
// 被增强的方法执行
proceedingJoinPoint.proceed();
System.out.println(“环绕之后~~~”);
}
}
对相同切入点进行抽取后,如果要修改相同切入点只需要更改公共切入点即可
3.9 多个增强类对同一个方法进行增强设置增强类优先级
3.9.1 @Order(数字类型值)
(1)在增强类上添加注解@Order(数字类型值),数字类型值越小优先级越高
@Component@Aspect//生产代理对象
@Order(3)
public class UserProxy {
// beforer注解表示作为前置通知
@Before(value = “pointdemo()”)
public void before() {
System.out.println(“before~~~”);
}
@Component@Aspect@Order(1)
public class PersonProxy {
@Before(value = “execution(* com.caq.spring5.aopano.User.add(…))”)
public void afterReturning(){
System.out.println(“Peoson Before…”);
}
测试
优先级更大的PersonProxy代理类先执行
Peoson Before…
before~~~
=============================================================================
4.1.1 什么是JdbcTemplate
(1) Spring框架对JDBC进行封装,使用JdbcTemplate方便实现对数据库操作
4.1.2 准备工作
在原有包的基础上引入新包~
在Spring配置文件配置数据库连接池,配置JdbcTemplate对象,注入DataSource
<?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.caq”></context:component-scan>
<bean id=“dataSource” class=“com.alibaba.druid.pool.DruidDataSource”
destroy-method=“close”>
创建service类,创建dao类,在dao注入jdbctemplate对象
4.2.1 Dao层
package com.caq.spring5.dao;
import com.caq.spring5.entity.Book;
public interface BookDao {
void add(Book book);
}
package com.caq.spring5.entity;
public class Book {
private String userId;
private String username;
private String ustatus;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUstatus() {
return ustatus;
}
public void setUstatus(String ustatus) {
this.ustatus = ustatus;
}
}
4.2.2 Services层
package com.caq.spring5.service;
import com.caq.spring5.dao.BookDao;
import com.caq.spring5.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BookService {
// 注入dao对象
@Autowired
private BookDao bookDao;
// 添加的方法
public void addBook(Book book){
bookDao.add(book);
}
}
xml文件
<?xml version="1.0" encoding="UTF-8"?><beans xmlns=“http://www.springframework.org/schema/beans”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
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.caq”></context:component-scan>
<bean id=“dataSource” class=“com.alibaba.druid.pool.DruidDataSource”
destroy-method=“close”>
4.2.3 测试
package com.caq.spring5.test;
import com.caq.spring5.entity.Book;
import com.caq.spring5.service.BookService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class testAdd {
@Test
public void testJdbcTemplate(){
// 1.解析xml文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(“bean1.xml”);
// 2.得到对象
BookService bookService = context.getBean(“bookService”, BookService.class);
// 3.调用方法
Book book = new Book();
book.setUserId(“1”);
book.setUsername(“php”);
book.setUstatus(“running”);
bookService.addBook(book);
}
}
4.3.1 Dao层
package com.caq.spring5.dao;
import com.caq.spring5.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class BookDaoImpl implements BookDao {
// 注入jdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
// 添加的方法
public void add(Book book) {
// 创建sql语句
String sql = “insert into t_book values(?,?,?)”;
// 调用方法实现
Object[] args = {book.getUserId(), book.getUsername(), book.getUstatus()};
int update = jdbcTemplate.update(sql, args);
System.out.println(update);//0,1,-1
}
// 修改
@Override
public void updateBook(Book book) {
String sql = “update t_book set username=?,ustatus=? where user_id=?”;
Object[] args = {book.getUsername(), book.getUstatus(), book.getUserId()};
int update = jdbcTemplate.update(sql, args);
System.out.println(update);//0,1,-1
}
// 删除
@Override
public void deleteBook(String id) {
String sql = “delete from t_book where user_id=?”;
int update = jdbcTemplate.update(sql, id);
System.out.println(update);//0,1,-1
}
}
4.3.2 Services层
package com.caq.spring5.service;
import com.caq.spring5.dao.BookDao;
import com.caq.spring5.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BookService {
// 注入dao对象
@Autowired
private BookDao bookDao;
// 添加的方法
public void addBook(Book book){
bookDao.add(book);
}
public void updateBook(Book book){
bookDao.updateBook(book);
}
public void deleteBook(String id){
bookDao.deleteBook(id);
}
}
4.3.3 测试
package com.caq.spring5.test;
import com.caq.spring5.entity.Book;
import com.caq.spring5.service.BookService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class testAdd {
@Test
public void testJdbcTemplate(){
// 1.解析xml文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(“bean1.xml”);
// 2.得到对象
BookService bookService = context.getBean(“bookService”, BookService.class);
// 修改的测试
Book book = new Book();
book.setUserId(“1”);
book.setUsername(“javanb”);
book.setUstatus(“Failed”);
bookService.updateBook(book);
// 删除的测试
bookService.deleteBook(“1”);
}
}
修改后
删除后
4.4 JdbcTemplate 操作数据库(查询返回对象)
下面只放关键代码了,全粘贴上去太浪费时间了
public int findCount(){
return bookDao.selectCount();
}
@Override
public int selectCount() {
String sql = " select count(*) from t_book";
Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
return count;
}
int count = bookService.findCount();
System.out.println(count);
一月 10, 2022 4:22:11 下午 com.alibaba.druid.support.logging.JakartaCommonsLoggingImpl info
信息: {dataSource-1} inited
2
4.5 JdbcTemplate 操作数据库(查询返回对象)
4.5.1 返回某个对象
// 根据id返回某个对象,类似于查看某个图书的详细信息,其实就是查看这个对象
public Book findOne(String id){
return bookDao.findBookInfo(id);
}
@Override
public Book findBookInfo(String id) {
String sql = “select * from t_book where user_id=?”;
// 调用方法
Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper(Book.class),id);
return book;
}
一月 10, 2022 4:39:15 下午 com.alibaba.druid.support.logging.JakartaCommonsLoggingImpl info
信息: {dataSource-1} inited
Book{userId=‘1’, username=‘a’, ustatus=‘S’}
4.5.2 返回集合对象
// 查询数据库中所有对象,返回一个集合
public List findAll(){
return bookDao.findAllBook();
}
@Override
public List findAllBook() {
String sql = “select * from t_book”;
List bookList = jdbcTemplate.query(sql, new BeanPropertyRowMapper(Book.class));
return bookList;
}
// 查询返回集合
List all = bookService.findAll();
System.out.println(all);
一月 10, 2022 4:47:21 下午 com.alibaba.druid.support.logging.JakartaCommonsLoggingImpl info
信息: {dataSource-1} inited
[Book{userId=‘1’, username=‘a’, ustatus=‘S’}, Book{userId=‘2’, username=‘b’, ustatus=‘F’}]
4.6.1 批量添加
// 批量添加
public void batchAddBook(List<Object[]> batchArgs){
bookDao.batchAddBook(batchArgs);
}
@Override
public void batchAddBook(List<Object[]> batchArgs) {
String sql = “insert into t_book values(?,?,?)”;
int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
System.out.println(Arrays.toString(ints));
}
List<Object[]> batchArgs = new ArrayList<>();
Object[] o1 = {“3”,“C”,“Success”};
Object[] o2 = {“4”,“C++”,“Success”};
Object[] o3 = {“5”,“C#”,“Success”};
batchArgs.add(o1);
batchArgs.add(o2);
batchArgs.add(o3);
// 调用批量添加
bookService.batchAddBook(batchArgs);
4.6.2 批量修改
public void batchUpdate(List<Object[]> batchArgs) {
bookDao.batchUpdate(batchArgs);
}
@Override
public void batchUpdate(List<Object[]> batchArgs) {
String sql = “update t_book set username=?,ustatus=? where user_id=?”;
int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
System.out.println(Arrays.toString(ints));
}
List<Object[]> batchArgs = new ArrayList<>();
Object[] o1 = {“Python”, “Success”, “3”};
Object[] o2 = {“Object-c”, “Success”, “4”};
Object[] o3 = {“Linux”, “Success”, “5”};
batchArgs.add(o1);
batchArgs.add(o2);
batchArgs.add(o3);
// 调用批量添加
bookService.batchUpdate(batchArgs);
一月 10, 2022 6:50:51 下午 com.alibaba.druid.support.logging.JakartaCommonsLoggingImpl info
信息: {dataSource-1} inited
[1, 1, 1]
4.6.3 批量删除
// 批量删除
public void batchDelete(List<Object[]> batchArgs) {
bookDao.batchDelete(batchArgs);
}
@Override
public void batchDelete(List<Object[]> batchArgs) {
String sql = “delete from t_book where user_id=?”;
int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
System.out.println(Arrays.toString(ints));
}
List<Object[]> batchArgs = new ArrayList<>();
Object[] o1 = {“3”};
Object[] o2 = {“4”};
Object[] o3 = {“5”};
batchArgs.add(o1);
batchArgs.add(o2);
batchArgs.add(o3);
// 调用批量添加
bookService.batchDelete(batchArgs);
一月 10, 2022 7:00:19 下午 com.alibaba.druid.support.logging.JakartaCommonsLoggingImpl info
信息: {dataSource-1} inited
[1, 1, 1]
=====================================================================
5.1.1 什么是事物?
事物是数据库操作最基本单元,逻辑上一组操作,要么都成功要么都失败,如果有一个失败所有操作都失败
5.1.2 事物的特性(ACID)
(1)原子性(Atomicity)
一组事物要么都成功要么都失败
(2)一致性(Consistency)
操作之前和操作之后它的总量是不变的
(3)隔离性(Isolation)
即一个事务内部的操作及正在操作的数据必须封锁起来,不被其它企图进行修改的事务看到。
两人同时去操作同一条数据,这个过程是不会产生影响的
(4)持久性(Durability)
事物提交,表中数据发生变化
事务添加到JavaEE三层结构里面Service层(业务逻辑层)因为是业务层对数据进行操作
在 Spring进行事务管理操作
(1)有两种方式:编程式事务管理和声明式事务管理(使用)
3、声明式事务管理
(1)基于注解方式(使用)
(2)基于xml 配置文件方式
4、在 Spring进行声明式事务管理,底层使用AOP原理
5、Spring事务管理API
(1)提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类
5.3.1 在spring配置文件配置事务管理器
5.3.2 在 spring 配置文件,开启事务注解
(1)在 spring 配置文件引入名称空间 tx
<?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”
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">
<context:component-scan base-package=“com.caq”></context:component-scan>
<bean id=“dataSource” class=“com.alibaba.druid.pool.DruidDataSource”
destroy-method=“close”>
<tx:annotation-driven transaction-manager=“transactionManager”></tx:annotation-driven>
(2)开启事务注解
<tx:annotation-driven transaction-manager=“transactionManager”></tx:annotation-driven>
5.3.3 在 service 类上面(或者 service 类里面方法上面)添加事务注解
@Transactional,这个注解添加到类上面,也可以添加方法上面
如果把这个注解添加类上面,这个类里面所有的方法都添加事务
如果把这个注解添加方法上面,为这个方法添加事务
5.4.1 @Transactional相关参数
5.4.2 propagation:事务传播行为
(1)事物方法?
事物方法就是对数据库表数据进行变化的操作,如增加删除数据的方法就是事物方法
(2)事物传播行为?
指的就是当一个事物方法被另一个事务方法调用时,这个事务改如何进行
例如当A事物方法调用B事物方法时,B是继续在A事物方法中运行呢,还是为自己新开一个事物运行呢,这就是B事物方法传播行为决定的~
这里视频讲的一笔带过了,想了解详细的话要去补一下mysql基础!
视频这里主要是讲这些在spring中怎么配置
Spring框架事务传播行为有7种
主要了解这两种
REQUIRED
如果add方法本身有事务,调用update方法之后,update使用当前add方法里面事务
如果add方法本身没有事务,调用update方法之后,创建新事务
REQUIRED_NEW
使用add方法调用updato方法,如果add无论是否有事务,都创建新的事务
5.4.3 ioslation:事务隔离级别
(1)事务并发可能出现的情况
脏读(Dirty Read)
一个事务读到了另一个未提交事务修改过的数据
会话B开启一个事务,把id=1的name为武汉市修改成温州市,此时另外一个会话A也开启一个事务,读取id=1的name,此时的查询结果为温州市,会话B的事务最后回滚了刚才修改的记录,这样会话A读到的数据是不存在的,这个现象就是脏读。(脏读只在读未提交隔离级别才会出现)
不可重复读(Non-Repeatable Read)
一个事务只能读到另一个已经提交的事务修改过的数据,并且其他事务每对该数据进行一次修改并提交后,该事务都能查询得到最新值。(不可重复读在读未提交和读已提交隔离级别都可能会出现)
会话A开启一个事务,查询id=1的结果,此时查询的结果name为武汉市。接着会话B把id=1的name修改为温州市(隐式事务,因为此时的autocommit为1,每条SQL语句执行完自动提交),此时会话A的事务再一次查询id=1的结果,读取的结果name为温州市。会话B再此修改id=1的name为杭州市,会话A的事务再次查询id=1,结果name的值为杭州市,这种现象就是不可重复读。
幻读(Phantom)
一个事务先根据某些条件查询出一些记录,之后另一个事务又向表中插入了符合这些条件的记录,原先的事务再次按照该条件查询时,能把另一个事务插入的记录也读出来。(幻读在读未提交、读已提交、可重复读隔离级别都可能会出现)
会话A开启一个事务,查询id>0的记录,此时会查到name=武汉市的记录。接着会话B插入一条name=温州市的数据(隐式事务,因为此时的autocommit为1,每条SQL语句执行完自动提交),这时会话A的事务再以刚才的查询条件(id>0)再一次查询,此时会出现两条记录(name为武汉市和温州市的记录),这种现象就是幻读。
(2)事务的隔离级别
通过设置事物的隔离级别来解决读问题
MySQL的事务隔离级别一共有四个,分别是读未提交、读已提交、可重复读以及可串行化。
MySQL的隔离级别的作用就是让事务之间互相隔离,互不影响,这样可以保证事务的一致性。
隔离级别比较:可串行化>可重复读>读已提交>读未提交
隔离级别对性能的影响比较:可串行化>可重复读>读已提交>读未提交
由此看出,隔离级别越高,所需要消耗的MySQL性能越大(如事务并发严重性),为了平衡二者,一般建议设置的隔离级别为可重复读,MySQL默认的隔离级别也是可重复读。
读未提交(READ UNCOMMITTED)
在读未提交隔离级别下,事务A可以读取到事务B修改过但未提交的数据。
可能发生脏读、不可重复读和幻读问题,一般很少使用此隔离级别。
读已提交(READ COMMITTED)
在读已提交隔离级别下,事务B只能在事务A修改过并且已提交后才能读取到事务A修改的数据。
读已提交隔离级别解决了脏读的问题,但可能发生不可重复读和幻读问题,一般很少使用此隔离级别。
可重复读(REPEATABLE READ)
在可重复读隔离级别下,事务B只能在事务A修改过数据并提交后,自己也提交事务后,才能读取到事务A修改的数据
可重复读隔离级别解决了脏读和不可重复读的问题,但可能发生幻读问题。
提问:为什么上了写锁(写操作),别的事务还可以读操作?
因为InnoDB有MVCC机制(多版本并发控制),可以使用快照读,而不会被阻塞。
可串行化(SERIALIZABLE)
各种问题(脏读、不可重复读、幻读)都不会发生,通过加锁实现(读锁和写锁)。
(3)四种隔离级别的比较
spring中的默认情况(不写括号里的内容,默认是这些)
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
5.4.4 timeout:超时时间
(1)事务需要在一定时间内进行提交,如果不提交进行回滚
(2)默认值是-1,设置时间以秒单位进行计算
5.4.5 readOnly:是否只读
(1)读:查询操作,写:添加修改删除操作
(2) readOnly 默认值false,表示可以查询,可以添加修改删除操作
(3)设置readOnly值是true,设置成true之后,只能查询
5.4.6 rollbackFor:回滚
(1)设置出现哪些异常进行事务回滚
5.4.7 noRollbackFor:不回滚
(1)设置出现哪些异常不进行事务回滚
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
总结
蚂蚁面试比较重视基础,所以Java那些基本功一定要扎实。蚂蚁的工作环境还是挺赞的,因为我面的是稳定性保障部门,还有许多单独的小组,什么三年1班,很有青春的感觉。面试官基本水平都比较高,基本都P7以上,除了基础还问了不少架构设计方面的问题,收获还是挺大的。
经历这次面试我还通过一些渠道发现了需要大厂真实面试主要有:蚂蚁金服、拼多多、阿里云、百度、唯品会、携程、丰巢科技、乐信、软通动力、OPPO、银盛支付、中国平安等初,中级,高级Java面试题集合,附带超详细答案,希望能帮助到大家。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
csdn.net/qq_45714272/article/details/122450296)读未提交(READ UNCOMMITTED)
在读未提交隔离级别下,事务A可以读取到事务B修改过但未提交的数据。
可能发生脏读、不可重复读和幻读问题,一般很少使用此隔离级别。
读已提交(READ COMMITTED)
在读已提交隔离级别下,事务B只能在事务A修改过并且已提交后才能读取到事务A修改的数据。
读已提交隔离级别解决了脏读的问题,但可能发生不可重复读和幻读问题,一般很少使用此隔离级别。
可重复读(REPEATABLE READ)
在可重复读隔离级别下,事务B只能在事务A修改过数据并提交后,自己也提交事务后,才能读取到事务A修改的数据
可重复读隔离级别解决了脏读和不可重复读的问题,但可能发生幻读问题。
提问:为什么上了写锁(写操作),别的事务还可以读操作?
因为InnoDB有MVCC机制(多版本并发控制),可以使用快照读,而不会被阻塞。
可串行化(SERIALIZABLE)
各种问题(脏读、不可重复读、幻读)都不会发生,通过加锁实现(读锁和写锁)。
(3)四种隔离级别的比较
spring中的默认情况(不写括号里的内容,默认是这些)
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
5.4.4 timeout:超时时间
(1)事务需要在一定时间内进行提交,如果不提交进行回滚
(2)默认值是-1,设置时间以秒单位进行计算
5.4.5 readOnly:是否只读
(1)读:查询操作,写:添加修改删除操作
(2) readOnly 默认值false,表示可以查询,可以添加修改删除操作
(3)设置readOnly值是true,设置成true之后,只能查询
5.4.6 rollbackFor:回滚
(1)设置出现哪些异常进行事务回滚
5.4.7 noRollbackFor:不回滚
(1)设置出现哪些异常不进行事务回滚
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。[外链图片转存中…(img-dDdZBxRR-1713334609353)]
[外链图片转存中…(img-wrrFd8N8-1713334609354)]
[外链图片转存中…(img-1uEe6K36-1713334609354)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
总结
蚂蚁面试比较重视基础,所以Java那些基本功一定要扎实。蚂蚁的工作环境还是挺赞的,因为我面的是稳定性保障部门,还有许多单独的小组,什么三年1班,很有青春的感觉。面试官基本水平都比较高,基本都P7以上,除了基础还问了不少架构设计方面的问题,收获还是挺大的。
经历这次面试我还通过一些渠道发现了需要大厂真实面试主要有:蚂蚁金服、拼多多、阿里云、百度、唯品会、携程、丰巢科技、乐信、软通动力、OPPO、银盛支付、中国平安等初,中级,高级Java面试题集合,附带超详细答案,希望能帮助到大家。
[外链图片转存中…(img-q1CTq2pN-1713334609354)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!