一 简介

  • 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
 	@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 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 {
 	@Autowired
 	private 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{
    @Override
    public String getBelief() {
        return "I believe I can fly!";
    }

    @Override
    public 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) {
    	//被代理的类型1
        SuperMan superMan = new SuperMan();
        Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);  // 强转为对应接口的类型
        // invoke() 方法: 当我们的动态代理对象调用原生方法的时候,最终实际上调用到的是 invoke() 方法,然后 invoke() 方法代替我们去调用了被代理对象的原生方法。
        String belief = proxyInstance.getBelief();
        proxyInstance.eat("四川麻辣烫");

		//被代理的类型2
        NikeClothFactory 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("环绕通知:后");
    }
}

  • 测试过程与结果
    @Test
    public 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 {
    @Autowired
    private UserDAO userDAO;
    
    // 提供的服务,调用对应的 DAO...
}


/*DAO 类*/
@Component(value = "userDAO")
public class UserDAOImpl implements UserDAO {
    @Autowired
    private JdbcTemplate jdbcTemplate;

	// 单精度的表操作实现...
}

2 添加 / 修改 / 删除 操作

在 DAO 中调用 jdbcTemplate 的 update 方法

@Component(value = "userDAO")
public class UserDAOImpl implements UserDAO {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public 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);
    }
}

测试方法:

    @Test
    public 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 {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public 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 {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public 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 {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    @Override
    public 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 {

    //创建数据库连接池
    @Bean
    public 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对象
    @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;
    }
}
Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐