后端学习 - Spring5

文章目录

  • 一 简介
  • 二 IOC
    • 1 底层原理
    • 2 实现过程
    • 3 Spring 实现 IOC 的两个接口
  • 二 Bean
    • 1 普通 Bean 与 FactoryBean
    • 2 Bean 单例与否的设置
    • 3 Bean 的生命周期
  • 三 IOC 的 Bean 管理(XML)
    • 1 创建对象
    • 2 属性注入 - 使用 set 方法
    • 3 属性注入 - 通过有参构造器实现
    • 3 注入属性为 null / 包含特殊符号
    • 4 注入外部 Bean
    • 5 注入内部 Bean
    • 6 注入 array / list / map / set
    • 7 自动装配
    • 8 使用外部文件配置 Bean
  • 四 IOC 的 Bean 管理(注解)
    • 1 Spring 针对创建 Bean 对象提供的注解
    • 2 创建对象的步骤
    • 3 属性注入 - @Autowared
    • 4 属性注入 - @Qualifier
    • 5 属性注入 - @Resource
    • 6 属性注入 - @Value
    • 7 完全注解开发
  • 五 AOP 概述
    • 1 动态代理的两种情况
    • 2 JDK 动态代理实例
  • 六 AspectJ 的使用(注解)
    • 1 切入点表达式
    • 2 使用流程
    • 3 相同切入点的抽取
    • 4 完全注解开发
  • 七 JdbcTemplate
    • 1 配置
    • 2 添加 / 修改 / 删除 操作
    • 3 查询值
    • 4 查询单个对象
    • 5 查询多个对象
  • 八 Spring 事务管理
    • 1 注解声明式事务管理的步骤
    • 2 @Transactional 的参数配置
    • 3 完全注解的 声明式事务管理


一 简介

  • Spring 是轻量级的开源的 JavaEE 框架
  • Spring 有两个核心部分:IOC(Inversion of Control,控制反转) 和 AOP(Aspect Oriented Programming,面向切面编程)
  • IOC 是一种设计思想,核心是,将设计好的对象交给容器控制,而不是传统的在对象内部直接控制。 把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散的耦合。
  • AOP 是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。简言之,AOP 可以做到不修改源代码进行功能增强。OOP 面向名词领域,AOP 面向动词领域。

二 IOC

1 底层原理

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

2 实现过程

  1. 配置 xml 文件的 bean 标签,使用 id 属性标注对象名,使用 class 属性标注类所在的位置,在 bean 标签内部使用 property 标签绑定依赖关系
<bean id="studentDAO" class="dao.StudentInfoDAO"><property name="..." value="...">
</bean>
  1. 使用工厂类,利用反射机制,创建对象
class MyFactory {public DAO getDAO () {String classValue = // 经过一些方法得到"dao.StudentInfoDAO";  // 解析xml,获取bean标签的class属性值Class clazz = Class.forName(classValue);  // 获取指定类的 Class 对象return (StudentInfoDAO)clazz.newInstance();  // 根据 Class 对象创建实例}
} 

经过上述过程,各类间进一步解耦。例如,此时 xml 配置中,class 属性变动不会对其创建造成影响。

3 Spring 实现 IOC 的两个接口

  1. BeanFactory:Spring 内部的使用接口,不提供给开发人员进行使用。加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象
  2. ApplicationContext:BeanFactory 接口的子接口,功能更强大,加载配置文件时候就会把在配置文件对象进行创建。 把创建资源的过程放在服务器启动时。有两个实现类:FileSystemXmlApplicationContext (传入 xml 文件的绝对路径)和 ClassPathXmlApplicationContext (传入 xml 文件的相对路径,以 src 作为起始目录)

二 Bean

1 普通 Bean 与 FactoryBean

  • 普通 Bean 的定义类型和返回类型相同,而 FactoryBean 的定义类型和返回类型可以不同
  • 要创建 FactoryBean,需要实现接口 FactoryBean<T>
<bean id="myBean" class="com.atguigu.spring5.factorybean.MyBean"></bean>
public class MyBean implements FactoryBean<Course> {  // 返回类型是Course@Overridepublic Course getObject() throws Exception {Course course = new Course();course.setCname("abc");return course;}@Overridepublic Class<?> getObjectType() {return null;}@Overridepublic boolean isSingleton() {return false;}
}

2 Bean 单例与否的设置

  • 默认 Bean 是单例对象
  • 通过 Bean 标签的 scope="singleton" / "prototype" 选择单例与否
  • 设置 scope = "singleton" ,加载 spring 配置文件时候就会创建单实例对象;设置 scope = "prototype" ,在调用 getBean 方法时候创建多实例对象

3 Bean 的生命周期

(1)通过构造器创建 bean 实例(无参构造)
(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
(3)把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization(可选)
(4)调用 bean 的初始化的方法(需要配置初始化的方法)
(5)把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization(可选)
(6)bean 可以使用(获取到了对象)
(7)当容器关闭时候,调用 bean 的销毁的方法(需要配置销毁的方法)

后置处理器在配置后,会对所有的 Bean 生效

不含后置处理器的 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 destroyMethod() {System.out.println("第五步 执行销毁的方法");}
}

三 IOC 的 Bean 管理(XML)

Bean 管理包含两个步骤:创建对象、注入属性

1 创建对象

创建对象时候,默认是执行无参数构造方法完成对象创建。

<bean id="custom_instance_name" class="pojo.MyClass"></bean>

  • id:唯一标识,相当于对象名
  • class:类全路径

2 属性注入 - 使用 set 方法

  1. 在 Bean 中实现要注入属性的 set 方法
public class Book {//创建属性private String bname;private String bauthor;//创建属性对应的 set 方法public void setBname(String bname) {this.bname = bname;}public void setBauthor(String bauthor) {this.bauthor = bauthor;}
}
  1. 在 xml 文件中配置要注入的属性名,以及属性值
<bean id="book" class="com.atguigu.spring5.Book"><!--name:类里面属性名称    value:向属性注入的值--><property name="bname" value="易筋经"></property><property name="bauthor" value="达摩老祖"></property>
</bean>

3 属性注入 - 通过有参构造器实现

  1. 创建类,定义属性,创建有参构造器
public class Orders {//属性private String oname;private String address;//有参构造public Orders(String oname,String address) {this.oname = oname;this.address = address;}
  1. 在 xml 文件中配置,constructor-arg 指定了调用有参数的构造器
<bean id="orders" class="com.atguigu.spring5.Orders"><!--constructor-arg 指定了调用有参数的构造器!--><!--也可以使用index属性代替name属性--><constructor-arg name="oname" value="电脑"></constructor-arg><constructor-arg name="address" value="China"></constructor-arg>
</bean>

3 注入属性为 null / 包含特殊符号

<bean id="book" class="com.atguigu.spring5.Book"><property name="address"><null/></property><property name="tel"><value><![CDATA[...]]></value></property>
</bean>

4 注入外部 Bean

  • 示例使用 set 方法进行注入,要求 userService 实现了其 dao 属性的 set 方法
  • name 是类里面属性名称,ref 是创建 userDao 对象 bean 标签 id
<bean id="userService" class="com.atguigu.spring5.service.UserService"><!--注入 userDao 对象name 属性:类里面属性名称ref 属性:创建 userDao 对象 bean 标签 id 值--><property name="userDao" ref="userDaoImpl"></property>
</bean><bean id="userDaoImpl" class="com.atguigu.spring5.dao.UserDaoImpl"></bean>

5 注入内部 Bean

  • 示例使用 set 方法进行注入
  • 如果注入的类型是 Bean,则将 value 标签替换为 ref 标签
<!--内部 bean-->
<bean id="emp" class="com.atguigu.spring5.bean.Emp"><!--设置对象类型属性--><property name="dept"><bean id="dept" class="com.atguigu.spring5.bean.Dept"><property name="dname" value="安保部"></property></bean></property>
</bean>

6 注入 array / list / map / set

  • 示例使用 set 方法进行注入
<bean id="stu" class="com.atguigu.spring5.collectiontype.Stu"><!--数组类型属性注入--><property name="courses"><array><value>java 课程</value><value>数据库课程</value></array></property><!--list 类型属性注入--><property name="list"><list><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>MySQL</value><value>Redis</value></set></property>
</bean><bean ...><!--注入 list 集合类型,值是对象--><property name="courseList"><list><ref bean="course1"></ref><ref bean="course2"></ref></list></property>
</bean>

7 自动装配

  • bean 标签后设置属性 autoware
  • 可选参数 byName(根据属性的名称,自动装配和属性名相同的 id 的 bean 对象);byType(根据属性类型,自动装配 bean 对象)

8 使用外部文件配置 Bean

以 Druid 数据库连接池的配置为例。

<!--引入 context 名称空间-->
.......<!--引入外部属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${prop.driverClass}"></property><property name="url" value="${prop.url}"></property><property name="username" value="${prop.userName}"></property><property name="password" value="${prop.password}"></property>
</bean>

四 IOC 的 Bean 管理(注解)

使用注解的目的是简化 xml 配置

1 Spring 针对创建 Bean 对象提供的注解

  • @Component
  • @Service
  • @Controller
  • @Repository

以上注解的功能相同,只是用于标识不同层

2 创建对象的步骤

  1. 加入依赖包
  2. 更改 xml 的名称空间(略),开启组件扫描(如果扫描多个包,在一个双引号中用逗号隔开)
    <context:component-scan base-package="com.atguigu"></context:component-scan>
  3. 创建类并使用对应的注解
// value的默认值是 userService
@Component(value = "userService") //相当于xml方式的 <bean id="userService" class=".."/>
public class UserService {public void add() {System.out.println("service add.......");}
}

3 属性注入 - @Autowared

  • 根据属性类型进行自动装配
  • 创建 service 和 dao 对象,在 service 和 dao 类添加对应的创建对象注解;在 service 注入 dao 对象,在 service 类添加 dao 类型属性,在属性上使用注解
  • 不需要为注入属性添加 set 方法
@Service  // 等同于 @Service(value="userService")  等同于  <bean id="userService" class="...">
public class UserService {@Autowiredprivate UserDao userDao;public void add() {System.out.println("service add.......");userDao.add();}

4 属性注入 - @Qualifier

  • 根据名称注入
  • 和上面的 @Autowired 一起使用,用于区别相同类型的不同 Bean
@Service
public class UserService {@Autowired // 根据类型进行注入@Qualifier(value = "userDaoImpl1") // 根据名称进行注入private UserDao userDao;public void add() {System.out.println("service add.......");userDao.add();}

5 属性注入 - @Resource

  • 可以实现类型注入、名称注入
  • 类型注入不需要加参数,名称注入使用 name 参数指定

6 属性注入 - @Value

  • 上述三种注入的是对象属性,而 @Value 可以注入普通类型
@Value(value = "abc")
private String name;

7 完全注解开发

  • 使用 @Configuration 注解的类,代替配置文件
  • 使用 @ComponentScan(basePackages = {"..."}) 完成组件扫描
@Configuration
@ComponentScan(basePackages = {"com.atguigu"})
public class SpringConfig {}
  • 使用时加载配置类:ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
@Test
public void testService2() {// 加载配置类ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);// 后续操作相同UserService userService = context.getBean("userService", UserService.class);// ...
}

五 AOP 概述

Aspect Oriented Programming,面向切面编程,本质是动态代理

  • 连接点:类中可以被增强的方法
  • 切入点:实际增强的方法
  • 通知(增强):实际增强的逻辑部分,包含 前置通知 / 后置通知 / 环绕通知 / 异常通知(增强发生异常时的逻辑) / 最终通知(增强部分类似于 finally)
  • 切面:通知应用到切入点的过程

1 动态代理的两种情况

  1. 需要代理的类具有接口,使用 JDK 动态代理,创建接口实现类代理对象(向代理类中传入接口的实现类)
  2. 需要代理的类不具有接口,使用 GCLIB 动态代理,创建其子类的代理对象

2 JDK 动态代理实例

  1. 接口与接口的实现
interface Human{String getBelief();void eat(String food);
}class SuperMan implements Human{@Overridepublic String getBelief() {return "I believe I can fly!";}@Overridepublic void eat(String food) {System.out.println("我喜欢吃" + food);}
}
  1. 动态代理类:动态代理对象调用原生方法的时候,最终实际上调用到的是 invoke() 方法,然后 invoke() 方法调用了被代理对象的原生方法。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class DebugInvocationHandler implements InvocationHandler {// 代理类中的真实对象private final Object target;public DebugInvocationHandler(Object target) {this.target = target;}/*** 动态代理的核心部分!!!* proxy :动态生成的代理类* method : 与代理类对象调用的方法相对应* args : 当前 method 方法的参数**/public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {//额外操作...Object result = method.invoke(self.target, args); //调用的是method的invoke方法//额外操作...return result;}
}
  1. 获取代理对象的工厂类:输入需要被代理的对象,输出其代理。即:根据对象实例建立代理实例。
public class JdkProxyFactory {public static Object getProxy(Object target) {return Proxy.newProxyInstance(target.getClass().getClassLoader(), // 目标类的类加载target.getClass().getInterfaces(),  // 代理需要实现的接口,可指定多个new DebugInvocationHandler(target)   // 代理对象对应的自定义 InvocationHandler);}
}
  1. 实际使用:一个代理,到处使用
    public static void main(String[] args) {//被代理的类型1SuperMan superMan = new SuperMan();Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);  // 强转为对应接口的类型// invoke() 方法: 当我们的动态代理对象调用原生方法的时候,最终实际上调用到的是 invoke() 方法,然后 invoke() 方法代替我们去调用了被代理对象的原生方法。String belief = proxyInstance.getBelief();proxyInstance.eat("四川麻辣烫");//被代理的类型2NikeClothFactory nikeClothFactory = new NikeClothFactory();ClothFactory proxyClothFactory = (ClothFactory);				ProxyFactory.getProxyInstance(nikeClothFactory);proxyClothFactory.produceCloth();}

六 AspectJ 的使用(注解)

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

1 切入点表达式

  • 用于设置增强方法(在代理类中的注解的 value 属性

  • 语法规则:execution([权限修饰符(可选)] [返回类型(可为*)] [类全路径] [方法名称]([参数列表]) )

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

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

2 使用流程

  1. 引入依赖(略)
  2. 配置 xml,更改名称空间,开启组件扫描、代理对象生成
<beans>...<!--开启组件扫描--><context:component-scan base-package="pojo"></context:component-scan><!--生成代理对象--><aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
  1. 被代理类、原方法、代理类、增强方法注解。用 @Aspect 注解代理类
  • 被代理类与原方法
@Component(value = "myClass")
public class MyClass {public void add() {System.out.println("原来的add方法");}
}
  • 代理类与增强方法
@Component(value = "enhanceClass")
@Aspect
public class EnhanceClass {@Before(value = "execution(* pojo.MyClass.add(..))")public void before() {System.out.println("前置通知");}@AfterReturning(value = "execution(* pojo.MyClass.add(..))")public void afterReturning() {System.out.println("后置通知,正常返回时才执行");}@After(value = "execution(* pojo.MyClass.add(..))")public void after() {System.out.println("最终通知,无论是否正常返回都执行");}@AfterThrowing(value = "execution(* pojo.MyClass.add(..))")public void afterThrowing() {System.out.println("异常通知");}@Around(value = "execution(* pojo.MyClass.add(..))")public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {System.out.println("环绕通知:前");proceedingJoinPoint.proceed();System.out.println("环绕通知:后");}
}
  • 测试过程与结果
    @Testpublic void testAspect() {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("myclass.xml");MyClass myClass = applicationContext.getBean("myClass", MyClass.class);myClass.add();}/*
执行结果:环绕通知:前前置通知未增强的方法环绕通知:后最终通知,无论是否正常返回都执行后置通知,正常返回时才执行
*/

3 相同切入点的抽取

对空方法使用注解 @Pointcut(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
相同切入点的注解的 value 属性值为 “空方法调用”

@Component(value = "enhanceClass")
@Aspect
public class EnhanceClass {@Pointcut(value="execution(* pojo.MyClass.add(..))")public void myPointCut() {}@Before(value = "myPointCut")public void before() {System.out.println("前置通知");}
}

4 完全注解开发

创建配置类代替 xml

@Configuration
@ComponentScan(basePackages = {"pojo"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop {}

七 JdbcTemplate

1 配置

  1. 引入依赖
  2. 使用 xml 配置 Druid 数据库连接池,创建 JdbcTemplate,并注入数据库连接池
    <!-- 数据库连接池 --><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"><property name="url" value="jdbc:mysql://localhost:3306/test" /><property name="username" value="root" /><property name="password" value="123" /><property name="driverClassName" value="com.mysql.cj.jdbc.Driver" /></bean><!--创建jdbctemplate,注入数据库连接池--><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"></property></bean>
  1. 创建 Service 类,注入 DAO;创建 DAO,注入 JdbcTemplate
    在 xml 中配置组件扫描 <context:component-scan base-package="jdbc"></context:component-scan>
/*Service 类*/
@Service(value = "userService")
public class UserService {@Autowiredprivate UserDAO userDAO;// 提供的服务,调用对应的 DAO...
}/*DAO 类*/
@Component(value = "userDAO")
public class UserDAOImpl implements UserDAO {@Autowiredprivate JdbcTemplate jdbcTemplate;// 单精度的表操作实现...
}

2 添加 / 修改 / 删除 操作

在 DAO 中调用 jdbcTemplate 的 update 方法

@Component(value = "userDAO")
public class UserDAOImpl implements UserDAO {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic void add(User user) {String sql = "insert into user values (?, ?, ?, ?, ?)";Object[] args = {user.getId(), user.getName(), user.getPwd(), user.getAddr(), user.getTel()};int update = this.jdbcTemplate.update(sql, args);  // 调用 jdbcTemplate.update 进行添加System.out.println(update);}
}

测试方法:

    @Testpublic void testAddOneItem() {User user = new User(10, "伍佰", "500", "老城路101", "554433");ApplicationContext applicationContext = new ClassPathXmlApplicationContext("myclass.xml");UserService userService = applicationContext.getBean("userService", UserService.class);userService.addUser(user);}
  • 如果要实现批量操作,调用 jdbcTemplate 的 batchUpdate
  • batchUpdate传入的参数1为 sql,参数2为List<Object[]> 类型,其中的每个元素 Object[] 代表一条语句的参数

3 查询值

在 DAO 中调用 jdbcTemplate 的 queryForObject 方法

@Component(value = "userDAO")
public class UserDAOImpl implements UserDAO {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic int selectCount() {String sql = "select count(*) from user";return this.jdbcTemplate.queryForObject(sql, Integer.class);}
}

4 查询单个对象

  • 在 DAO 中调用 jdbcTemplate 的 queryForObject 方法
  • 需要传入 BeanPropertyRowMapper 对象,其作用是将 SQL 查询返回值封装为指定对象
  • 默认情况下需要表属性名和类属性名一致
@Component(value = "userDAO")
public class UserDAOImpl implements UserDAO {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic User selectById(int id) {String sql = "select * from user where id = ?";User user = this.jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), id);return user;}
}

5 查询多个对象

类似于查询单个对象,调用的是 query 方法

@Component(value = "userDAO")
public class UserDAOImpl implements UserDAO {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic List<User> selectAll() {String sql = "select * from user";List<User> userList = this.jdbcTemplate.query(sql, new BeanPropertyRowMapper<User>(User.class));return userList;}
}

八 Spring 事务管理

  • 底层使用了 AOP 原理
  • 事务方法:更改数据库内容的方法(增删改)
  • 在 Web - Service - DAO 三层结构中,推荐把事务注解放在 Service 层
  • Spring 提供了一个事务管理器接口 PlatformTransactionManager ,这个接口针对不同的框架提供不同的实现类

在这里插入图片描述

1 注解声明式事务管理的步骤

  1. 更改 Spring 配置文件:创建事务管理器、注入数据源,引入名称空间 tx,同时开启事务注解
    <!--创建事务管理器,注入数据库连接池--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property></bean><!--开启事务注解--><tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
  1. @Transactional 可以用于类(注解类中的所有方法),也可以用于方法

2 @Transactional 的参数配置

  1. propagation(事务传播行为):多事务方法进行调用,这个过程中事务是如何进行管理的
  2. isolation(隔离级别):可选属性 读未提交 / 读提交 / 可重复读 / 串行化
  3. timeout(超时时间):超时后自动回滚,以秒为单位,默认-1
  4. readOnly(是否只读):默认为 flase,如果设置为 true 则只能查询
  5. rollbackFor(回滚):指定出现哪些异常进行回滚
  6. noRollbackFor(不回滚):指定出现哪些异常不执行回滚

3 完全注解的 声明式事务管理

@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:///user_db");dataSource.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;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/307169.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

吐槽一下Abp的用户和租户管理模块

1. 背景ASP.NET Core 基于声明的访问控制到底是什么鬼&#xff1f;聊到基于声明的身份认证将 身份和签发机构分离&#xff0c;应用程序信任签发机构&#xff0c;故认可签发的身份信息。-----------ClaimB站:438962688 Name:饭思思_weibo:538210234 Name:饭思思van姓名:不详 籍贯…

后端学习 - JDBC

文章目录一 JDBC概述1 Java中的数据存储技术2 什么是JDBC3 JDBC程序的编写步骤二 Java连接数据库的方式三 使用 PreparedStatement 实现 CRUD 操作1 数据库的调用的三个接口2 增Create/删Delete/改Update 操作3 查Retrieval操作4 批量插入操作四 数据库事务1 事务2 事务的 ACID…

后端学习 - JavaWeb

技术体系 文章目录一 HTML1 网页的组成部分2 HTML 概述3 HTML 标签4 常用标签5 表单与表单的提交二 CSS1 语法格式2 使用方法三 JavaScript1 概述2 与 HTML 结合的两种方式3 变量类型及特殊值4 关系、逻辑运算5 数组6 函数7 事件8 DOM &#xff08;Document Object Model&#…

心想技术驱动业务,却在背道而驰

这里是Z哥的个人公众号每周五11&#xff1a;45 按时送达当然了&#xff0c;也会时不时加个餐&#xff5e;我的第「165」篇原创敬上大家好&#xff0c;我是Z哥。相信每一位真正的程序员心里都有这样一个念想&#xff1a;只要我的技术够牛&#xff0c;就能驱动业务的发展。但是往…

后端学习 - SpringMVC

文章目录一 SpringMVC 简介1 MVC2 SpringMVC3 创建第一个 SpringMVC 项目二 RequestMapping1 注解类与方法的区别2 value 属性3 method 属性4 params 属性5 headers 属性6 SpringMVC 支持路径中的占位符三 获取 Request 的一系列参数1 通过控制器方法的形参2 控制器方法形参 映…

hbase shell远程连接_hbase与phoenix集成

Phoenix是构建在HBase之上的关系型数据库层&#xff0c;作为内嵌的客户端JDBC驱动用以对HBase中的数据进行低延迟访问Phoenix会将用户编写的sql查询编译为一系列的scan操作&#xff0c;最终产生通用的JDBC结果集返回给客户端Phoenix可以看成是mysql准备安装包apache-phoenix-4.…

对精致码农大佬的 [理解 volatile 关键字] 文章结论的思考和寻找真相

一&#xff1a;背景1. 讲故事昨天在园里的编辑头条看到 精致码农大佬 写的一篇题为&#xff1a;[C#.NET 拾遗补漏]10&#xff1a;理解 volatile 关键字 (https://www.cnblogs.com/willick/p/13889006.html) 的文章&#xff0c;大概就是说在 多线程环境下&#xff0c;一个在debu…

后端学习 - SpringBoot

SpringBoot 是整合 Spring 技术栈的一站式框架&#xff0c;是简化 Spring 技术栈的快速开发脚手架约定大于配置 文章目录一 概述1 第一个 SpringBoot 项目2 SpringBoot 特性&#xff1a;依赖管理3 SpringBoot 特性&#xff1a;自动配置二 SpringBoot 的 IOC容器1 组件添加&…

centos rpm 安装 perl_Linux【常用软件安装篇】

摘要&#xff1a;本文介绍Linux常用的软件安装方式以及jdk、vim、mysql、tomcat、redis的安装过程。1 Linux常用软件安装方式常用方式有&#xff1a;rmp包安装、yum指令安装、源码包安装、解压免安装。1.1 rpm包安装rpm是Red-Hat Package Manager&#xff08;RPM软件包管理器&a…

日计不足涓滴成河-自定义响应结果格式化器

什么是响应结果响应结果就是&#xff0c;在客户端向服务器发出请求后&#xff0c;服务器根据客户端的请求参数&#xff0c;给出的结果&#xff0c;这就是一个完整的响应结果过程。响应的结果包含的内容非常多&#xff0c;主要的有 HTTP Status Code&#xff0c;Content-Type,Co…

docker 容器启动顺序_Docker容器启动时初始化Mysql数据库

1. 前言 Docker在开发中使用的越来越多了&#xff0c;最近搞了一个Spring Boot应用&#xff0c;为了方便部署将Mysql也放在Docker中运行。那么怎么初始化 SQL脚本以及数据呢&#xff1f; 我这里有两个传统方案。 第一种方案是在容器启动后手动导入&#xff0c;太low了不行。第二…

后端学习 - JVM(上)内存与垃圾回收

JVM 架构图 文章目录一 JVM 简介二 类加载子系统&#xff1a;1 作用2 类的三个加载过程3 类加载器的分类4 双亲委派机制 & Tomcat为何不遵循5 两个 class 对象为同一个类的必要条件三 运行时数据区&#xff1a;PC寄存器&#xff08;Program Counter Register&#xff09;四…

SM2 国密算法被 Linux 内核社区接受

喜欢就关注我们吧&#xff01;10 月 25 日&#xff0c;有开发者发文称&#xff0c;SM2 国密算法终于被 Linux 内核社区接受了。该作者表示&#xff0c;SM2 的补丁已经更新到了 v7 版本&#xff0c;这个版本的补丁最终被社区接受&#xff0c;目前已经合并到了 Linux 主线的 5.10…

后端学习 - MyBatis

MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的 持久层框架 文章目录一 基于配置文件的 MyBatis 搭建1 搭建过程&#xff08;增删改&#xff09;2 查询操作3 特殊操作二 MyBatis 获取参数值的方式1 单个字面量类型的参数2 多个字面量类型的参数3 Map 类型的参数4 实体…

国产操作系统发展离不开人才和市场

日前&#xff0c;中国 1024 程序员节盛大举行&#xff0c;一大批开源大咖齐聚千年岳麓&#xff0c;围绕开源标准、生态、人才发展等主题分享&#xff0c;共议开源软件与操作系统未来。其中&#xff0c;统信软件总经理刘闻欢表示&#xff0c;“有了市场才会被真正的用起来”&…

后端学习 - Redis

文章目录一 Redis 概述Redis 为什么是单线程&#xff0c;单线程为什么这么快&#xff1f;数据存储结构二 常用数据类型1 String2 HashHash 的扩容机制&#xff1a;渐进式 rehash*3 List4 Set5 Zset三 Redis 事务1 乐观锁与 watch 命令2 事务的三个特性四 Redis 持久化1 RDB(Red…

再被补刀!Flash又遭抛弃,你会怀念它吗?

喜欢就关注我们吧&#xff01;微软近日发布通知&#xff0c;称更新了关于 Adobe Flash Player 的删除。微软更新目录站点可下载更新 KB4577586&#xff0c;用于删除 Flash Player。此更新适用于所有受支持的操作系统版本。重要版本 Windows 10 和 Windows 8.1 的可选更新也将在…

4位加法器的设计代码verilog_HDLBits:在线学习Verilog(六 · Problem 25-29)

本系列文章将和读者一起巡礼数字逻辑在线学习网站 HDLBits 的教程与习题&#xff0c;并附上解答和一些作者个人的理解&#xff0c;相信无论是想 7 分钟精通 Verilog&#xff0c;还是对 Verilog 和数电知识查漏补缺的同学&#xff0c;都能从中有所收获。附上传送门&#xff1a;M…

译 | 将数据从Cosmos DB迁移到本地JSON文件

点击上方蓝字关注“汪宇杰博客”原文&#xff1a;Azure Tips and Tricks翻译&#xff1a;汪宇杰在Cosmos DB中使用数据迁移工具有一项重复的任务是将数据从一种数据库格式迁移到另一种数据库格式。我最近使用Cosmos DB作为数据库来存储Ignite大会发出的所有推文。然而一旦获得了…

在线教育后端开发项目总结

文章目录一 数据库访问接口1 MyBatis2 Spring Data JPA3 Spring Data MongoDB二 数据库1 MySQL2 MongoDB3 Redis三 开发规范化、响应格式与异常处理1 开发规范2 响应格式3 异常处理四 RabbitMQ五 Spring Cloud 相关工具1 Eureka2 Ribbon3 Feign4 Zuul 网关六 搜索服务1 Elastic…