注:以下信息是从各种渠道收集来的信息进行整合!!!
目录
第一部分 开发环境和配置概述
第二部分 JSP&Servlet
第三部分 MyBatis
第四部分 Spring
第1章 初识Spring框架
1. Spring介绍
1.1 Spring框架的核心技术
Spring是由Rod Johnson组织和开发的一个分层的Java SE/EE一站式(full-stack)轻量级开源框架。它最为核心的理念是IoC(控制反转)和AOP(面向切面编程),其中,IoC是Spring的基础,它支撑着Spring对JavaBean的管理功能;AOP是Spring 的重要特性,AOP是通过预编译方式和运行期间动态代理实现程序功能,也就是说可以在不修改源代码的情况下,给程序统一添加功能。
1.2 Spring在表现层、业务逻辑层和持久层的作用
- 在表现层它提供了Spring MVC框架,并且Spring还可以与Struts 框架整合。
- 在业务逻辑层可以管理事务、记录日志等。
- 在持久层可以整合MyBatis、Hibernate、JdbcTemplate等技术。
1.3 String框架的优点
- 非侵入式设计
Spring是一种非侵入式(non-invasive)框架,所谓非侵入式是指Spring框架的API不会在业务逻辑上出现,也就是说业务逻辑应该是纯净的,不能出现与业务逻辑无关的代码。由于业务逻辑中没有Spring的API,所以业务逻辑代码也可以从Spring框架快速地移植到其他框架。 - 降低耦合性
Spring就是一个大工厂,可以将所有对象的创建和依赖关系的维护工作都交给Spring容器管理,大大降低了组件之间的耦合性。 - 支持AOP编程
Spring提供了对AOP的支持,AOP可以将一些通用的任务进行集中处理,如安全、事务和日志等,以减少通过传统OOP方法带来的代码冗余和繁杂。 - 支持声明式事务
在Spring中,可以直接通过Spring配置文件管理数据库事务,省去了手动编程的繁琐,提高了开发效率。 - 方便程序的测试
Spring提供了对Junit的支持,开发人员可以通过Junit进行单元测试。 - 方便集成框架
Spring提供了一个广阔的基础平台,其内部提供了对各种框架的直接支持,如Struts、Hibernate、MyBatis、Quartz等,这些优秀框架可以与Spring无缝集成。 - 降低Java EE API的使用难度
Spring对Java EE开发中的一些API(如JDBC、JavaMail等)都进行了封装,大大降低了这些API的使用难度。
1.4 Spring 5的体系结构图
Spring 5框架主要有七大模块,每个大模块由多个或1个小模块组成,如Spring的核心容器模块(Core Container)是由Beans模块、Core模块、Context模块和SpEL模块组成。
1.4.1 核心容器模块(Core Container)
核心容器模块在Spring的功能体系中起着支撑性作用,是其他模块的基石。核心容器层主要由Beans模块、Core模块、Contex模块和SpEL模块组成。
- Beans模块。它提供了BeanFactory类,是工厂模式的经典实现,Beans模块的主要作用是创建和管理Bean对象。
- Core模块。它提供了Spring框架的基本组成部分,包括IoC和DI功能。
- Context模块。它构建于Beans模块和Core模块的基础之上,它可以通过ApplicationContext接口提供上下文信息。
- SpEL模块。它是Spring 3.0后新增的模块,提供了对SpEL表达式语言(Spring Expression Language)的支持,SpEL表达式语言是一个在程序运行时支持操作对象图的表达式语言。
1.4.2 数据访问及集成模块(Data Access/Integration)
数据访问及集成模块用于访问和操作数据库中的数据,它主要包含JDBC模块、ORM模块、OXM模块、JMS模块和Transactions模块。
- JDBC模块。它提供了一个JDBC的抽象层,消除了冗长的JDBC编码并能够解析数据库供应商特有的错误代码。
- ORM模块。它为主流的对象关系映射API提供了集成层,用于集成主流的对象关系映射框架。
- OXM模块。它提供了对XML映射的抽象层的支持,如JAXB、Castor等。
- JMS模块。它主要用于传递消息,包含消息的生产和消费。自4.1版本后,JMS模块支持与Spring-message模块的集成。
- Transactions模块。它的主要功能是事务管理。
1.4.3 Web模块
Web模块的实现基于APPlicationContext基础之上,它提供了Web应用的各种工具类,包括了Web模块、Servlet模块、WebSocket模块和Portlet模块。
- Web模块。它提供了针对Web开发的集成特性,如大部分文件上传功能等。此外,Web模块还包含一个HTTP客户端和Spring远程处理支持的Web相关部分。
- Servlet模块。它提供了Spring的模型、视图、控制器以及Web应用程序的REST Web服务实现。
- WebSocket模块。它是Spring 4.0以后新增的模块,它提供了WebSocket 和SockJS的实现,以及对STOMP的支持。
- Portlet模块。它类似Servlet模块的功能,提供了Portlet环境下的MVC实现。
1.4.4 其他模块
- AOP模块。它提供了对面向切面编程的支持,程序可以定义方法拦截器和切入点,将代码按照功能进行分离,以降低程序的耦合性。
- Aspects模块。它提供了与AspectJ集成的支持。
- Instrumentation模块。它提供了对类工具的支持,并且实现了类加载器,该模块可以在特定的应用服务器中使用。
- Messaging模块。它是Spring 4.0以后新增的模块,它提供了对消息传递体系结构和协议的支持。
- Test模块。它提供了对程序单元测试和集成测试的支持。
1.5 Spring目录结构下文件夹介绍
- docs文件夹:该文件夹下存放Spring的相关文档,包括开发指南、API参考文档。
- libs文件夹:该文件夹下存放开发所需的jar包和源码。整个Spring框架由21个模块组成,libs目录下Spring为每个模块都提供了三个压缩包,因此,libs文件夹下一共有63个jar包。这63个jar包分为三类。
- schema文件夹:该文件夹下存放Spring各种配置文件的XML Schema文档。
2. 控制反转与依赖注入
2.1 控制反转的概念
IoC控制反转机制指的是对象由Ioc容器统一管理,当程序需要使用对象时,可以直接从IoC容器中获取。这样对象的控制权就从应用程序转移到了IoC容器。
它是借助于IoC容器实现具有依赖关系对象之间的解耦,各个对象类封装之后,通过IoC容器来关联这些对象类。
2.2 依赖注入的概念
依赖注入(Dependency Inject,缩写DI)就是由IoC容器在运行期间动态地将某种依赖资源注入对象之中。例如,将对象B注入(赋值)给对象A的成员变量。依赖注入的基本思想是:明确地定义组件接口,独立开发各个组件,然后根据组件的依赖关系组装运行。
2.2.1 依赖注入的实现方式
- 构造方法注入
构造方法注入是指Spring容器调用构造方法注入被依赖的实例,构造方法可以是有参的或者是无参的。Spring在读取配置信息后,会通过反射方式调用实例的构造方法,如果是有参构造方法,可以在构造方法中传入所需的参数值,最后创建类对象。
<bean id="user1" class="com.example.User">
<constructor-arg name="id" value="1"></constructor-arg>
<constructor-arg name="name" value="张三"></constructor-arg>
<constructor-arg name="password" value="123456"></constructor-arg>
</bean>
注:一个<constructor-arg>元素表示构造方法的一个参数,且定义时不区分顺序,只需要通过<constructor-arg>元素的name属性指定参数即可。<constructor-arg>元素还提供了type属性类指定参数的类型,避免字符串和基本数据类型的混淆。
- setter属性注入
属性setter方法注入是Spring最主流的注入方法,这种注入方法简单、直观,它是在被注入的类中声明一个setter方法,通过setter方法的参数注入对应的值。
<bean id="user2" class="com.example.User">
<property name="id" value="2"></property>
<property name="name" value="李四"></property>
<property name="password" value="123456"></property>
</bean>
2.3 依赖注入和控制反转的比较
依赖注入(DI)和控制反转(IoC)是从不同角度来描述了同一件事情。依赖注入是从应用程序的角度描述,即应用程序依赖IoC容器创建并注入它所需要的外部资源;而控制反转是从IoC容器的角度描述,即IoC容器控制应用程序,由IoC容器反向地向应用程序注入应用程序所需要的外部资源。这里所说的外部资源可以是外部实例对象,也可以是外部文件对象等。
第2章 Spring中的Bean的管理
1. Spring IoC容器
1.1 BeanFactory接口
Spring提供了几个BeanFactory接口的实现类,其中最常用的是XmlBeanFactory,它可以读取XML文件并根据XML文件中的配置信息生成BeanFactory接口的实例,BeanFactory接口的实例用于管理Bean。XmlBeanFactory类读取XML文件生成BeanFactory接口实例的具体语法格式为:
BeanFactory beanFactory=new XmlBeanFactory (new FileSystemResource("./bean.xml"));
常用方法:
1.2 ApplicationContext接口
ApplicationContext接口建立在BeanFactory接口的基础之上,它丰富了BeanFactory接口的特性,例如,添加了对国际化、资源访问、事件传播等方面的支持。
ApplicationContext接口可以为单例的Bean实行预初始化,并根据元素执行setter方法,单例的Bean可以直接使用,提升了程序获取Bean实例的性能。
ApplicationContext接口的常用实现类:
2. Bean的配置
2.1 Spring容器所支持的配置文件格式
Spring容器支持XML和Properties两种格式的配置文件,在实际开发中,最常用的是XML格式的配置文件。XML是标准的数据传输和存储格式,方便查看和操作数据。在Spring中,XML配置文件的根元素是<beans>,<beans>元素包含<bean>子元素,每个<bean>子元素可以定义一个Bean,通过<bean>元素将Bean注册到Spring容器中。
2.1.1 < bean >元素的常用属性
2.1.2 < bean >元素的常用子元素
示例:
<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">
<!--使用id属性定义bean1,对应的实现类为com.example.Bean1-->
<bean id="bean1" class="com.example.Bean"></bean>
<!--使用name属性定义bean2,对应的实现类为com.example.Bean2-->
<bean name="bean2" class="com.example.Bean"/>
</beans>
3. Bean的实例化
3.0 Bean类
package com.example;
public class Bean {
public Bean(){
System.out.println("Bean 创建成功!");
}
}
3.1 方法1——构造方法实例化
在applicationContext.xml中配置:
<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">
<bean id="bean" class="com.example.Bean"></bean>
</beans>
3.2 方法2——静态工厂实例化
public class MyBeanFactory {
// 使用MyBeanFactory类的工厂创建Bean实例
public static Bean createBean(){
return new Bean();
}
}
在applicationContext.xml中配置:
<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-4.3.xsd">
<bean id="bean" class="com.example.MyBeanFactory" factory-method="createBean"/>
</beans>
3.3 方法3——实例工厂实例化
public class MyBeanFactory {
public MyBeanFactory() {
System.out.println("工厂 创建成功!");
}
// 创建Bean实例的方法
public Bean createBean() {
return new Bean();
}
}
在applicationContext.xml中配置:
<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-4.3.xsd">
<!-- 配置工厂 -->
<bean id="myBeanFactory" class="com.example.MyBeanFactory" />
<!-- 使用factory-bean属性指向配置的实例工厂-->
<bean id="bean3" factory-bean="myBeanFactory" factory-method="createBean" />
</beans>
3.4 测试类
public class Test {
public static void main(String[] args){
// 加载applicationBean.xml配置
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationBean.xml");
// 通过容器获取配置中bean的实例
Bean bean=(Bean) applicationContext.getBean("bean");
}
}
4. Bean的作用域
在applicationContext.xml中配置:
<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">
<bean id="bean" class="com.example.Bean" scope="singleton"></bean>
</beans>
5. Bean的装配方式
5.1 基于XML的装配
在基于XML的装配就是读取XML配置文件中的信息完成依赖注入,Spring容器提供了两种基于XML的装配方式,属性setter方法注入和构造方法注入。
5.2 基于注解的装配
常见注解:
在applicationContext.xml中引入context约束并启动Bean的自动扫描功能。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.example" />
</beans>
service层:
@Service("orderService")
public class OrderServiceImpl implements OrderService {
@Autowired
public OrderMapper orderMapper;
@Override
public Page<Order> listByPage(Page<Order> page) {
...
}
@Override
public Order delivery(Integer orderId) {
...
}
}
controller层:
@Controller
public class OrderController {
@Autowired
public OrderService orderService;
public String list(Model model, @RequestParam(required = false) Integer start) {
...
}
public String delivery(@RequestParam Integer orderId) {
...
}
}
5.3 自动装配
Spring的<bean>元素中包含一个autowire属性,可以通过设置autowire属性的值实现Bean的自动装配。
6. Bean的生命周期
6.1 Bean在不同作用域内的生命周期
Bean的生命周期是指Bean实例被创建、初始化和销毁的过程。在Bean的两种作用域singleton和prototype中,Spring容器对Bean的生命周期的管理是不同的。在singleton作用域中,Spring容器可以管理Bean的生命周期,控制着Bean的创建、初始化和销毁。在prototype作用域中, Spring容器只负责创建Bean实例,不会管理其生命周期。
6.2 Bean生命周期的两个时间节点
在Bean的生命周期中,有两个时间节点尤为重要,这两个时间节点分别是Bean实例初始化后和Bean实例销毁前,在这两个时间节点通常需要完成一些指定操作。因此,常常需要对这两个节点进行监控。
6.3 监控时间节点的方式
监控两个节点的方式有两种,一种是使用XML配置文件,一种是使用注解。
Spring容器提供了@PostConstruct用于监控Bean对象初始化节点,提供了@PreDestroy用于监控Bean对象销毁节点。
@Component("student")
public class Student {
@Value("1")
private String id;
@Value("张三")
private String name;
// 省略getter/setter方法,以及toString()方法
@PostConstruct
public void init(){
System.out.println("Bean 初始化完成!");
}
@PreDestroy
public void destroy(){
System.out.println("Bean 即将销毁!");
}
}
第3章 Spring AOP
1. Spring AOP概述
AOP的全称是Aspect Oriented Programming,即面向切面编程。和OOP不同,AOP主张将程序中相同的业务逻辑进行横向隔离,并将重复的业务逻辑抽取到一个独立的模块中,以达到提高程序可重用性和开发效率的目的。
在传统的业务处理代码中,通常都会进行事务处理、日志记录等操作。虽然使用OOP可以通过组合或者继承的方式来达到代码的重用,但如果要实现某个功能(如日志记录),同样的代码仍然会分散到各个方法中。
AOP可以将事务管理的业务逻辑抽取到一个可重用的模块,进而降低横向业务逻辑之间的耦合,减少重复代码。AOP的使用,使开发人员在编写业务逻辑时可以专心于核心业务,而不用过多地关注其他业务逻辑的实现,不但提高了开发效率,又增强了代码的可维护性。
2. Spring AOP术语
AOP并不是一个新的概念,AOP中涉及很多术语,如切面、连接点、切入点、通知/增强处理、目标对象、织入、代理等等。
- 切面(Aspect)
切面是指关注点形成的类(关注点是指类中重复的代码),通常是指封装的、用于横向插入系统的功能类(如事务管理、日志记录等)。在实际开发中,该类被Spring容器识别为切面,需要在配置文件中通过<bean>元素指定。 - 连接点(JoinPoint)
连接点是程序执行过程中某个特定的节点,例如,某方法调用时或处理异常时。在Spring AOP中,一个连接点通常是一个方法的执行。 - 切入点(Pointcut)
当某个连接点满足预先指定的条件时,AOP就能够定位到这个连接点,在连接点处插入切面,该连接点也就变成了切入点。 - 通知/增强处理(Advice)
通知/增强处理就是插入的切面程序代码。可以将通知/增强处理理解为切面中的方法,它是切面的具体实现。 - 目标对象(Target)
目标对象是指被插入切面的方法,即包含主业务逻辑的类对象。或者说是被一个或者多个切面所通知的对象。 - 织入(Weaving)
将切面代码插入到目标对象上,从而生成代理对象的过程。织入可以在编译时,类加载时和运行时完成。在编译时进行织入就是静态代理,而在运行时进行织入则是动态代理。 - 代理(Proxy)
将通知应用到目标对象之后,程序动态创建的通知对象,就称为代理。代理类既可能是和原类具有相同接口的类,也可能就是原类的子类,可以采用调用原类相同的方式调用代理类。
3. Spring AOP的实现机制
3.1 Spring AOP的默认代理方式——JDK动态代理
默认情况下,Spring AOP使用JDK动态代理,JDK动态代理是通过java.lang.reflect.Proxy 类实现的,可以调用Proxy类的newProxyInstance()方法创建代理对象。JDK动态代理可以实现无侵入式的代码扩展,并且可以在不修改源代码的情况下,增强某些方法。
public class MyProxy implements InvocationHandler {
private UserDao userDao;
public Object createProxy(UserDao userDao) {
this.userDao = userDao;
ClassLoader classLoader = MyProxy.class.getClassLoader(); // 类加载器
Class[] classes = userDao.getClass().getInterfaces(); // 被代理对象实现的所有接口
return Proxy.newProxyInstance(classLoader,classes,this); // 3.返回代理对象
}
// 所有动态代理类的方法调用,都会交由invoke()方法去处理。这里省略invoke()方法
注:newProxyInstance()方法的3个参数
- 第1个参数是classLoader,表示当前类的类加载器。
- 第2个参数是classes,表示被代理对象实现的所有接口。
- 第3个参数是this,表示代理类JdkProxy本身。
public class Test {
public static void main(String[] args) {
MyProxy myProxy = new MyProxy(); // 创建代理对象
UserDao userDao = new UserDao(); // 创建目标对象
UserDao userDaoPlus = (UserDao) myProxy.createProxy(userDao); // 从代理对象中获取增强后的目标对象
userDaoPlus.addUser(); // 执行方法
}}
3.2 CGLib动态代理
JDK动态代理存在缺陷,它只能为接口创建代理对象,当需要为类创建代理对象时,就需要使用CGLib(Code Generation Library)动态代理,CGLib动态代理不要求目标类实现接口,它采用底层的字节码技术,通过继承的方式动态创建代理对象。Spring的核心包已经集成了CGLib所需要的包,所以开发中不需要另外导入JAR包。
public class MyProxy implements MethodInterceptor {
// 代理方法
public Object createProxy(Object target) {
Enhancer enhancer = new Enhancer(); // 创建一个动态类对象
enhancer.setSuperclass(target.getClass()); // 确定需要增强的类,设置其父类
enhancer.setCallback(this); // 添加回调函数
return enhancer.create(); // 返回创建的代理类
}
// intercept()方法省略
}
public class Test {
public static void main(String[] args) {
MyProxy myProxy = new MyProxy(); // 创建代理对象
UserDao userDao = new UserDao(); // 创建目标对象
UserDao userDaoPlus = (UserDao) myProxy.createProxy(userDao); // 获取增强后的目标对象
userDaoPlus.addUser(); // 执行方法
}}
4. 基于XML的AOP实现
因为Spring AOP中的代理对象由IoC容器自动生成,所以开发者无须过多关注代理对象生成的过程,只需选择连接点、创建切面、定义切点并在XML文件中添加配置信息即可。
Spring提供了一系列配置Spring AOP的XML元素。
4.1 配置切面
在Spring的配置文件中,配置切面使用的是<aop:aspect>元素,该元素会将一个已定义好的Spring Bean转换成切面Bean,因此,在使用<aop:aspect>元素之前,要在配置文件中先定义一个普通的Spring Bean。Spring Bean定义完成后,通过<aop:aspect>元素的ref属性即可引用该Bean。配置<aop:aspect>元素时,通常会指定id和ref两个属性。
4.2 配置切入点
在Spring的配置文件中,切入点是通过<aop:pointcut>元素来定义的。当<aop:pointcut>元素作为<aop:config>元素的子元素定义时,表示该切入点是全局的,它可被多个切面共享;当<aop:pointcut>元素作为<aop:aspect>元素的子元素时,表示该切入点只对当前切面有效。定义<aop:pointcut>元素时,通常会指定id、expression属性。
Spring AOP切入点表达式的基本格式:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern ( param-pattern ) throws-pattern?)
参数说明:
modifiers-pattern:表示定义的目标方法的访问修饰符,如public、private等。
ret-type-pattern:表示定义的目标方法的返回值类型,如void、String等。
declaring-type-pattern:表示定义的目标方法的类路径,如com.example.Dao.UserDao。
name-pattern:表示具体需要被代理的目标方法,如add()。
param-pattern:表示需要被代理的目标方法包含的参数。
throws-pattern:表示需要被代理的目标方法抛出的异常类型。
?:表示该参数为可选参数
4.3 配置通知
在Spring的配置文件中,使用<aop:aspect>元素配置了5种常用通知,分别为前置通知、后置通知、环绕通知、返回通知和异常通知。
4.4 示例
public class AspectTest {
// 前置通知
public void before(JoinPoint joinPoint){
...
}
public void afterReturning(JoinPoint joinPoint){
...
}
public Object around(ProceedingJoinPoint proceedingJoinPoint)throws Throwable {
...
Object proceed = proceedingJoinPoint.proceed(); //切点方法
...
return proceed;
}
public void afterException(JoinPoint joinPoint){
...
}
public void after(JoinPoint joinPoint){
...
}
}
注:环绕通知代码和其他通知方式的代码有所不同,如果使用其他通知方式的格式会报空指针错误。详情访问:Spring MVC Aop注入遇到空指针bug
<aop:config><!-- 指定切点 -->
<aop:pointcut id="pointcut" expression="execution(* com.example.Dao.UserDao.*(..))"/>
<aop:aspect ref ="AspectTest"><!-- 指定切面 -->
<aop:before method="before" pointcut-ref="pointcut"/><!-- 指定前置通知 -->
<aop:after-returning method="afterReturning" pointcut-ref="pointcut"/><!-- 指定返回通知 -->
<aop:around method="around" pointcut-ref="pointcut"/><!-- 指定环绕方式 -->
<aop:after-throwing method="afterException" pointcut-ref="pointcut"/><!-- 指定异常通知 -->
<aop:after method="after" pointcut-ref="pointcut"/><!-- 指定后置通知 -->
</aop:aspect>
</aop:config>
5. 基于注解的AOP实现
@Aspect
@Component
public class Logcat {
@Pointcut("execution(* edu.fzu.tmall.service.*.*(..))")
public void pointCut(){}
@AfterReturning("pointCut()")
public void logcat(JoinPoint joinPoint){
...
}
@Around("pointCut()")
public Object test(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕前增强...");
Object proceed = proceedingJoinPoint.proceed(); //切点方法
System.out.println("环绕后增强...");
return proceed;
}
}
在applicationContext.xml中
<!-- 开启@aspectj的自动代理支持 -->
<aop:aspectj-autoproxy/>
第4章 Spring的数据库编程
1. Spring JDBC
针对数据库操作,Spring框架提供了JdbcTemplate类,JdbcTemplate是一个模板类,Spring JDBC中的更高层次的抽象类均在JdbcTemplate模板类的基础上创建。
JdbcTemplate类提供了操作数据库的基本方法,包括添加、删除、查询和更新。在操作数据库时,JdbcTemplate类简化了传统JDBC中的复杂步骤,这可以让开发人员将更多精力投入到业务逻辑中。
JdbcTemplate类提供了一些访问数据库时使用的公共属性,具体如下:
- DataSource:DataSource主要功能是获取数据库连接。在具体的数据操作中,它还提供对数据库连接的缓冲池和分布式事务的支持。
- SQLExceptionTranslator:SQLExceptionTranslator是一个接口,它负责对SQLException异常进行转译工作。
1.1 Spring JDBC的配置
- 配置数据源:包括数据库驱动、连接数据库url、连接数据库用户名、连接数据库密码。
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/><!-- 数据库驱动 -->
<property name="url" value="jdbc:mysql://localhost:3306/spring"/><!-- 连接数据库url -->
<property name="username" value="root"/><!-- 连接数据库用户名 -->
<property name="password" value="root"/><!-- 连接数据库密码 -->
</bean>
- 配置JDBC模板:必须使用默认数据源。
<bean id="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 默认必须使用数据源 -->
<property name="dataSource" ref="dataSource"/>
</bean>
- 配置注入类
<bean id="xxx" class="Xxx">
<property name="JdbcTemplate" ref="JdbcTemplate"/>
</bean>
...
在dataSource的4个属性中,需要根据数据库类型或者系统配置设置相应的属性值。例如,如果数据库类型不同,需要更改驱动名称;如果数据库不在本地,则需要将地址中的localhost替换成相应的主机IP;默认情况下,数据库端口号可以省略,但如果修改过MySQL数据库的端口号,则需要加上修改后的端口号。此外,连接数据库的用户名和密码需要与数据库创建时设置的用户名和密码保持一致。
1.2 CRUD
1.2.1 execute()
public class TestJdbcTemplate {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
JdbcTemplate jdTemplate = (JdbcTemplate) applicationContext.getBean("jdbcTemplate");
jdTemplate.execute("create table account(id int primary key auto_increment, username varchar(50), balance double)");
System.out.println("账户表account创建成功!");}
}
1.2.2 update()方法
<!--定义id为accountDao的Bean-->
<bean id="accountDao" class="com.example.AccountDaoImpl">
<!-- 将jdbcTemplate注入到accountDao实例中 -->
<property name="jdbcTemplate" ref="jdbcTemplate" />
</bean>
public class AccountDaoImpl implements AccountDao {
// 定义JdbcTemplate属性,此处省略setter方法
private JdbcTemplate jdbcTemplate;
// 这里只展示(添加账户)的操作
public int addAccount(Account account) {
String sql = "insert into account(username,balance) value(?,?)";
Object[] obj = new Object[] {account.getUsername(), account.getBalance()}; // 定义数组来存放SQL语句中的参数
return this.jdbcTemplate.update(sql, obj); // 执行添加操作,返回的是受SQL语句影响的记录条数
}
}
public class TestUpdateAccount {
public static void main(String[] args) {
ApplicationContext applicationContext =new ClassPathXmlApplicationContext("applicationContext.xml");
AccountDao accountDao = (AccountDao) applicationContext.getBean("accountDao");
Account account = new Account();
account.setId(1);
account.setUsername("user");
account.setBalance(200000.00);
int num = accountDao.updateAccount(account);
if (num > 0) {
System.out.println("成功修改了" + num + "条数据!");
}
else {
System.out.println("修改操作执行失败!");
}
}
}
1.2.3 query()方法
public Account findAccountById(int id) {
String sql = "select * from account where id = ?";
RowMapper<Account> rowMapper = new BeanPropertyRowMapper<Account>(Account.class); // 创建一个新的BeanPropertyRowMapper对象
return this.jdbcTemplate.queryForObject(sql, rowMapper, id); // 将id绑定到SQL语句中,通过RowMapper返回Object类型的单行记录
}
2. Spring事务管理概述
2.1 事务管理核心接口
- PlatformTransactionManager接口:可以根据属性管理事务。
- TransactionDefinition接口:用于定义事务的属性。
- TransactionStatus接口:用于界定事务的状态 。
2.1.1 PlatformTransactionManager接口
2.1.2 TransactionDefinition接口
TransactionDefinition接口中定义了事务描述相关的常量,其中包括了事务的隔离级别、事务的传播行为、事务的超时时间和是否为只读事务。下面对这几种常量做详细讲解。
- 事务的隔离级别
- 事务的传播行为
- 事务的超时时间
事务的超时时间是指事务执行的时间界限,超过这个时间界限,事务将会回滚。TransactionDefinition接口提供了TIMEOUT_DEFAULT常量定义事务的超时时间。 - 事务是否只读
当事务为只读时,该事务不修改任何数据,只读事务有助于提升性能,如果在只读事务中修改数据,会引发异常。
TransactionDefinition接口中除了提供事务的隔离级别、事务的传播行为、事务的超时时间和是否为只读事务的常量外,还提供了一系列方法来获取事务的属性。
2.1.3 TransactionStatus接口
2.2 Spring中的事务管理的两种方式
Spring中的事务管理分为两种方式,一种是传统的编程式事务管理,另一种是声明式事务管理。
- 编程式事务管理:通过编写代码实现的事务管理,包括定义事务的开始、正常执行后的事务提交和异常时的事务回滚。
- 声明式事务管理:通过AOP技术实现的事务管理,其主要思想是将事务管理作为一个“切面”代码单独编写,然后通过AOP技术将事务管理的“切面”代码植入到业务目标类中。
2.2.1 声明式事务管理
基于XML方式的声明式事务管理是通过在配置文件中配置事务规则的相关声明来实现的。在使用XML文件配置声明式事务管理时,首先要引入tx命名空间,在引入tx命名空间之后,可以使用<tx:advice>元素来配置事务管理的通知,进而通过Spring AOP实现事务管理。
<!-- 5.编写通知,需要编写对切入点和具体执行事务细节-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" isolation="DEFAULT" read-only="false" />
</tx:attributes>
</tx:advice>
<!-- 6.编写aop,使用AspectJ的表达式,让spring自动对目标生成代理-->
<aop:config>
<aop:pointcut expression="execution(* com.example.*.*(..))" id="txPointCut" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
2.2.2 基于注解方式的声明式事务
@Transactional的属性:
<!-- 前四步省略 -->
<!-- 1.配置数据源:数据库驱动;连接数据库的url;连接数据库的用户名;连接数据库的密码 -->
<!-- 2.配置JDBC模板:默认必须使用数据源 -->
<!-- 3.定义id为accountDao的Bean:将jdbcTemplate注入到AccountDao实例中 -->
<!-- 4.事务管理器,依赖于数据源 -->
<!-- 5.注册事务管理器驱动 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false)
public void transfer(String outUser, String inUser, Double money) {
this.jdbcTemplate.update("update account set balance = balance + ? where username = ?",money, inUser); // 收款时,收款用户的余额=现有余额+所汇金额
int i = 1/0; // 模拟系统运行时的突发性问题
this.jdbcTemplate.update("update account set balance = balance - ? where username = ?",money, outUser); // 汇款时,汇款用户的余额=现有余额-所汇金额
}