SSM框架-Spring

it2025-10-13  9


Spring


1. Spring概述

    Spring是应用full-stack轻量级框架,以IoC(Inverse Of Control : 控制反转)和AOP(Aspect Oriented Programming : 面向切面编程)为内核,提供了表现层SpringMVC和持久层Spring JDBC以及业务层事务管理等众多的企业级应用技术,还能整合开源世界中众多的第三方框架和类库。

2. Spring的优势

方便解耦,简化开发 通过Spring提供的IoC容器,可以将对象间的依赖关系交由Spring进行控制,编码硬编码所造成的过度程序耦合。 AOP编程支持 通过Spring的AOP功能,方便进行面向切面编程,许多不容易用传荣OOP实现的功能可以通过AOP轻松实现。 声明式事务的支持 可以简化在事务管理方面的代码,通过声明的方式进行灵活的事务管理,提高开发效率和质量 方便程序的测试 可以用非容器依赖的编程方式进行几乎所有的测试工作,测试的难度被降低了。 方便集成各种优秀框架 Spring提供了对各种邮箱框架的直接支持。 降低JavaEE API的使用难度 Spring对JavaEE API中的代码(JDBC、JavaMail、远程调用等)进行了封装,降低了使用API的难度。

3. Spring的IoC应用

1. 在Maven中导入Spring的坐标

<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> </dependencies>

2. Spring的主配置文件:applicationContext.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"> </beans> 简单的Spring配置文件 <!-- 配置service id : 唯一标识 class : 指定类的全类名 --> <bean id="accountService" class="com.hsh.study.service.impl.AccountServiceImpl"></bean> <!-- 配置dao --> <bean id="accountDao" class="com.hsh.study.dao.impl.AccountDaoImpl"></bean> 常见属性标签 bean标签:用于配置对象让Spring来创建。默认情况下Spring调用类中的无参构造函数,没有无参构造函数则不能创建成功 属性: id:给对象在容器总提供一个唯一标识。用于获取对象。class:指定类的全限定类名。用于反射创建对象,默认情况下调用无参构造函数scope:指定对象的作用范围。 singleton:默认值,单例对象prototype:多例的request:在WEB中,Spring创建一个Bean对象,将对象存入request域中。session:在WEB中,Spring创建一个Bean对象,将对象存入session域中。global session:在WEB中,应用在Porlet环境,如果没有Porlet环境那么globalSession相当于Session。 init-method:指定类中的初始化方法名称。destory-method:指定类中销毁方法的名称factory-method:指定生产对象的静态方法(使用静态工厂初始化Bean时)factory-bean:用于指定实例工厂bean的id(使用实例工厂初始化Bean时)factory-method:用于指定实例工厂中创建对象的方法(使用实例工厂初始化Bean时)

3. Spring的执行方法

使用ApplicaionContext接口获取Spring的容器:ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); 根据配置文件获取对象:AccountService accountService = ac.getBean("accountService",AccountService.class); 使用对象:accountService.saveAccount();

ApplicationContext和BeanFactory的区别:

BeanFactory是Spring容器中的顶层接口。ApplicationContext是BeanFactory的子接口。BeanFactory和ApplicationContext创建对象的时间点不同; BeanFactory:什么时候使用什么时候创建对象ApplicationContext:只要读取完配置文件,默认情况下就会创建对象。

4. Spring的依赖注入

依赖注入概念:在编写程序时,通过IoC(控制反转)将对象的创建交给了Spring,但是代码中不可能出现没有依赖的情况。IoC解耦只是降低了代码间的依赖关系,但不会完全消除。构造函数的注入(通过类中的构造函数给成员变量完成赋值的操作) 编写需要进行赋值的实体类 public class User { private String username; private Integer age; private Date birthday; public User(String username, Integer age, Date birthday) { this.username = username; this.age = age; this.birthday = birthday; } @Override public String toString() { return "User{" + "username='" + username + '\'' + ", age=" + age + ", birthday=" + birthday + '}'; } } 用配置文件通过构造函数对属性进行赋值 <!-- 通过构造器进行属性注入 --> <bean id="user" class="com.hsh.study.domain.User"> <!-- 通过<constructor-arg>标签对构造函数中的属性进行赋值 index:指定参数在构造函数参数列表的索引位置 type:指定参数在构造函数中的数据类型 name:指定参数在构造函数中的名称 ==--- 上面用于指定给谁赋值,下面指定赋什么值 ---== value:能赋值的类型为基本数据类型和String类型 ref:能赋值的类型是其他bean类型,必须通过配置文件配置bean --> <constructor-arg name="username" value="张三"></constructor-arg> <constructor-arg name="age" value="18"></constructor-arg> <constructor-arg name="birthday" ref="now"></constructor-arg> </bean> <!-- 引入日期 --> <bean id="now" class="java.util.Date"></bean> set方法的注入(常用) 编写需要进行赋值的实体类 public class User { private String username; private Integer age; private Date birthday; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } @Override public String toString() { return "User{" + "username='" + username + '\'' + ", age=" + age + ", birthday=" + birthday + '}'; } } 用配置文件通过构造函数对属性进行赋值 <!-- 通过set方法注入 --> <bean id="user" class="com.hsh.study.domain.User"> <!-- 通过<property>标签对属性进行赋值 name:找类中set方法后面的部分 ref:给属性赋值是其他bean类型 value:给属性赋值的是基本数据类型或者string类型 --> <property name="username" value="李四"></property> <property name="age" value="16"></property> <property name="birthday" ref="now"></property> </bean> <!-- 引入日期 --> <bean id="now" class="java.util.Date"></bean> 使用p名称空间注入(本质还是调用set方法) 编写需要进行赋值的实体类 public class User { private String username; private Integer age; private Date birthday; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } @Override public String toString() { return "User{" + "username='" + username + '\'' + ", age=" + age + ", birthday=" + birthday + '}'; } } 用配置文件通过构造函数对属性进行赋值 <!-- 导入p标签的约束文件 --> xmlns:p="http://www.springframework.org/schema/p" <!-- 通过p标签进行注入 --> <bean id="user" class="com.hsh.study.domain.User" p:username="王五" p:age="18" p:birthday-ref="now" ></bean> <!-- 引入日期 --> <bean id="now" class="java.util.Date" ></bean> 注入集合属性 编写需要进行赋值的实体类 public class Collection { private String[] myStrs; private List<String> myList; private Set<String> mySet; private Map<String,String> myMap; private Properties myProps; public void setMyStrs(String[] myStrs) { this.myStrs = myStrs; } public void setMyList(List<String> myList) { this.myList = myList; } public void setMySet(Set<String> mySet) { this.mySet = mySet; } public void setMyMap(Map<String, String> myMap) { this.myMap = myMap; } public void setMyProps(Properties myProps) { this.myProps = myProps; } public String[] getMyStrs() { return myStrs; } public List<String> getMyList() { return myList; } public Set<String> getMySet() { return mySet; } public Map<String, String> getMyMap() { return myMap; } public Properties getMyProps() { return myProps; } } 用配置文件通过构造函数对属性进行赋值 <!-- 集合的注入 --> <bean id="collection" class="com.hsh.study.domain.Collection"> <!-- 注入集合数据 List结构:array、List、Set Map结构:map、properties、entry --> <!-- 数组注入 --> <property name="myStrs"> <list> <value>AAA</value> <value>BBB</value> <value>CCC</value> </list> </property> <!-- list集合注入 --> <property name="myList"> <array> <value>AAA</value> <value>CCC</value> <value>BBB</value> </array> </property> <!-- set集合注入 --> <property name="mySet"> <set> <value>BBB</value> <value>AAA</value> <value>CCC</value> </set> </property> <!-- map集合注入 --> <property name="myMap"> <map> <entry key="111" value="AAA"></entry> <entry key="222" value="BBB"></entry> <entry key="333" value="CCC"></entry> </map> </property> <!-- Props注入 --> <property name="myProps"> <props> <prop key="333">AAA</prop> <prop key="222">CCC</prop> <prop key="111">BBB</prop> </props> </property> </bean>

5. Spring基于注解的使用

在Maven中导入Spring的坐标配置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" 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"> </bean> 在配置文件中开启对注解的支持 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 告知spring创建容器时要扫描的包 --> <context:component-scan base-package="com.hsh.study"></context:component-scan> </beans> Spring的常用注解 创建对象的:<bean id="" class="" ></bean> @Component() 将资源交由Spring进行管理,相当于在xml中配置<bean>标签默认属性为value,value即是hean的id,如果不指定value属性则默认id为当前类名,首字母小写 @Controller @Service @Repository 这三个注释的作用与@Component的作用一致,只不过提供了更加明确的语义化 @Controller:一般用于表现层@Service:一般用于业务层@Repository:一般用于持久层 用于注入数据的:<property name="" ref="" /> <property name="" value="" /> @Autowired 自动按照类型注入。当使用注解注入属性时,可以不用声明set方法。只能注入其他bean类型。当有多个类型匹配时,使用要注入的对象变量名称作为bean的id。 @Qualifier 在自动按照类型的基础上,再按照Bean的id注入。在给字段注入时不能独立使用,必须和@Autowired一起使用;但是给方法参数注入时可以独立使用。value:指定bean的id @Resource 直接按照Bean的id进行注入。也是只能注入其他Bean类型name:指定bean的id @Value 注入基本数据类型和String类型的数据value:用于指定值 用于改变作用范围的:<bean id="" class="" ==scope=""==> </bean> @Scope 指定bean的作用范围value:指定范围的值(==singleton==、==prototype==、request、session、globalsession) 和生命周期相关的:<bean id="" class="" ==init-method=""== ==destory-method=""== /> @PostConstruct 用于指定初始化方法 @PreDestroy 用于指定销毁方法 用于纯注解配置的注解 @Configuration 作用:用于指定当前类是一个spring的配置类,当创建容器时会从该类上加载注解。获取容器时需要使用AnnotationApplicationContext(有@Configuration注解的类.class)value:用于指定配置类的字节码注:当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写。 @ComponentScan 作用:用于指定Spring再初始化容器时要扫描的包。作用和在spring的xml配置文件中的<context:component-scan base-package="com.hsh.study" />的作用相同basePackages:用于指定要扫描的包,和注解中的value属性作用一致。 @Bean 作用:该注解只能写在方法上,表明使用此方法创建一个对象并放入Spring的容器中name:给当前的@Bean注解方法创建的对象指定一个名称 @PropertySource 作用:用于加载.properties文件中的配置。例如当配置数据源时,可以把连接数据库的信息写道properties配置文件中,使用注解指定配置文件的位置。value[]:用于指定properties文件位置。如果是在类路径下,需要写上==classpath:== @Import 作用:用于导入其他配置类,在引入其他配置时可以不用再写@Configuration注解。value[]:用于指定其他配置类的字节码 Spring使用XML和使用注解配置的优劣 使用注解的优势:配置简单,维护方便,适用于Bean的是实现类由用户自己开发使用XML的优势:修改时不需要改源码,不涉及重新编译和部署。适用于Bean来自第三方,使用其他的Bean。

6. Spring中使用纯注解配置

创建一个主配置类 //@Configuration @ComponentScan("com.hsh.study") @Import(JdbcConfig.class) @PropertySource("classpath:jdbcConfig.properties") public class SpringConfiguration { } 创建JDBC配置类 public class JdbcConfig { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; /** * 创建QueryRunner对象 * @param dataSource * @return */ @Bean(name = "runner") @Scope("singleton") public QueryRunner createQueryRunner(@Qualifier("ds1") DataSource dataSource){ return new QueryRunner(dataSource); } /** * 创建数据库连接对象 * @return */ @Bean("ds1") public DataSource createDataSource(){ try{ ComboPooledDataSource ds = new ComboPooledDataSource(); ds.setDriverClass(driver); ds.setJdbcUrl(url); ds.setUser(username); ds.setPassword(password); return ds; }catch (Exception e){ throw new RuntimeException(e); } } } 使用注释完成创建对象和注入 //1. 业务层 @Service("accountService") public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; @Override public List<Account> findAll() { return accountDao.findAll(); } } //2. 持久层 @Repository("accountDao") public class AccountDaoImpl implements AccountDao { @Autowired private QueryRunner runner; @Override public List<Account> findAll() { try { return runner.query("select * from account",new BeanListHandler<Account>(Account.class)); } catch (SQLException e) { throw new RuntimeException(e); } } } 测试 ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class); // 基于注解创建applicationContext AccountService accountService = applicationContext.getBean("accountService", AccountService.class); List<Account> accounts = accountService.findAll(); for (Account account1 : accounts){ System.out.println(account1); }

4. Spring整合Junit

1. 导入整合junit的jar包

<dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.2.RELEASE</version> </dependency>

2. 使用注解@RunWith代替原有运行器

@RunWith(SpringJUnit4ClassRunner.class) public class JdbcTest2 { @Test public void test() { } }

3. 使用@ContextConfiguration指定spring配置文件位置

@ContextConfiguration属性: locations属性:用于指定配置文件的位置。位于类路径下需使用classpath:表示。calsses属性:用于指定注解的类。当不使用xml时,需要用此属性指定注解类的位置。 应用 @RunWith(SpringJUnit4ClassRunner.class) // 使用XML配置文件时 @ContextConfiguration(locations = {"classpath:applicationContext.xml"}) // 使用注解时 @ContextConfiguration(classes = {config.SpringConfiguration.class}) public class JdbcTest2 { @Test public void test() { } }

4. 使用@Autowired给变量注入数据

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {config.SpringConfiguration.class}) public class JdbcTest2 { @Autowired private AccountService accountService; @Test public void test() { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class); accountService = applicationContext.getBean("accountService", AccountService.class); List<Account> accounts = accountService.findAll(); for (Account account1 : accounts){ System.out.println(account1); } } }

5. Spring的AOP

1. 概念:

AOP(Aspect Oriented Programming)面向切面编程。利用AOP对业务逻辑的各个部分进行隔离,从而降低业务逻辑各部分之间的耦合度

2. AOP的作用及优势

作用:在程序运行期间,在不修改源码的基础上对已有方法进行增强。优势:①减少重复代码②提高开发效率③维护方便

3. AOP中相关的术语

JoinPoint(连接点):连接点指的是哪些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点。Pointcut(切入点):切入点指的是对哪些连接点进行拦截的定义。Advice(通知/增强):通知是指拦截到JoinPoint后所做的事情便是通知。 通知的类型:前置通知,后置通知,异常通知,最终通知和环绕通知。 Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下,Introduction可以在运行期间为类动态的添加一些方法或者Field。Target(目标对象):代理的目标对象。Weaving(织入):指把增强应用到目标对象来创建新的代理对象的过程。Proxy(代理):一个类被AOP织入增强后,就产生了一个结果代理类。Aspect(切面):是切入点和通知(引介)的结合。

3. AOP的使用

在Maven中引入Spring的AOP坐标 <!-- AOP坐标 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.0.2.RELEASE</version> </dependency> 在spring的配置文件中导入约束 spring-AOP的约束头信息 <?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: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/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> </beans> spring-AOP的配置 execution表达式 在AOP中使用execution表达式首先要导入表达式的坐标 <!-- AOP使用execution表达式坐标 --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency> execution表达式的使用方法 普通的表达式:权限修饰符 返回值类型 包名.包名...类名.方法名(参数列表)标准表达式写法:public void com.hsh.study.service.impl.AccountServiceImpl.findAll() 权限修饰符可以省略,返回值类型使用通配符代替:* com.hsh.study.service.impl.AccountServiceImpl.findAll() 包名使用通配符代替,几个类几个通配符:* *.*.*.*.*.AccountServiceImpl.findAll() 包名可以使用..表示当前包及其子包:* *..AccountServiceImpl.findAll() 方法名和类名都可以使用通配符:* *..*.*() 参数列表: 基本数据类型直接写名称:int引用数据类型写包名.类名的方式 java.lang.String使用..表示有无参数均可,有参数可以为任意类型 全通配写法:execution(* *..*.*(..)) AOP的具体配置 基本配置 <!-- 首先导入对应的bean --> <bean id="accountService" class="..."></bean> <!-- 导入配置方法的bean --> <bean id="logger" class="..." ></bean> <!-- 配置aop --> <aop:config> <!-- 配置切入点表达式<aop:pointcut /> id:指定表达式唯一标识 expression:指定表达式内容 此标签写在<aop:aspect>内部表示当前切面可用 此标签写在<aop:aspect>外部表示所有切面可用 --> <aop:pointcut id="pt1" expression="execution(* *..*.*(..))"/> <!-- 配置切面 --> <aop:aspect id="logAdvice" ref="transactionManager"> <!-- 配置前置通知" --> <aop:before method="beforePringLog" pointcut-ref="pt1" /> <!-- 配置后置通知 --> <aop:after-returning method="afterReturningPringLog" pointcut-ref="pt1" /> <!-- 配置异常通知 --> <aop:after-throwing method="afterThrowingPringLog" pointcut-ref="pt1" /> <!-- 配置最终通知 --> <aop:after method="afterPringLog" pointcut-ref="pt1" /> <!-- 配置环绕通知 --> <!-- <aop:around method="aroundPrintLog" pointcut-ref="pt1" />--> </aop:aspect> </aop:config> 环绕通知配置 类中 public Object aroundPrintLog(ProceedingJoinPoint pjp){ Object resultValue = null; try{ // 得到方法执行所需的参数 Object[] args = pjp.getArgs(); // 执行前置通知 System.out.println("前置通知"); // 执行切入点方法 resultValue = pjp.proceed(args); // 执行后置通知 System.out.println("后置通知"); return resultValue; }catch (Throwable e){ System.out.println("异常通知"); throw new RuntimeException(e); }finally { System.out.println("最终通知"); } } * 配置文件中 <bean id="accountService" class="..."></bean> <bean id="logger" class="..." ></bean> <aop:config> <aop:pointcut id="pt1" expression="execution(* ...*(..))"/> <aop:aspect id="logAdvice" ref="transactionManager"> </aop:aspect> </aop:config> ``` 基于注解的Spring-AOP配置 在配置文件中导入AOP相关的约束头信息 <?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:aop="http://www.springframework.org/schema/aop" 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/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> </bean> 指定Spring注解所需扫描的包,并开启对注解AOP的支持 <!-- 需要扫描的包 --> <context:component-scan base-package="com.hsh.study"></context:component-scan> <!-- 开启对注解AOP的支持 --> <aop:aspectj-autoproxy/> 针对各实体类进行注解配置在通知类中使用注解进行通知 在通知类上使用@Aspect注释表明这是一个切面类 @Component("logger") @Aspect public class Logger { } 切入点表达式注解 @Aspect 作用:指定切入点表达式value:指定表达式的内容 针对AOP的四种状态对应的注释 @Before 作用:将当前方法看作前置通知value:用于指定切入点表达式,还可以指定切入点表达式的引用 @After-Returning 作用:将当前方法看作后置通知value:用于指定切入点表达式,还可以指定切入点表达式的引用 @AfterThrowing 作用:将当前方法看作异常通知value:同上 @After 作用:将当前方法看作最终通知value:同上 @Around 作用:将当前方法看作环绕通知value:同上 @Around("pt1()") //引入切入点时括号要加上 使用纯注解配置时 在配置类上使用注解:@EnableAspectJAutoProxy即可

6. Spring中的JdbcTemplate

1. 概念

JdbcTemplate是Spring框架中提供的一个对象,是对原始JDBC API的简单封装。其中提供了许多的操作模板类。

操作关系数据库:JdbcTemplate、HibernateTemplate操作nosql数据:RedisTemplate操作消息队列:JmsTemplate

2. 基于Spring的JdbcTemplate所必须的jar包或坐标

<!-- JdbcTemplate坐标 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!-- 事务控制坐标 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.0.2.RELEASE</version> </dependency>

3. Spring-JdbcTemplate的使用

1. 编写Spring的配置文件

导入spring-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"> </beans> 配置相应的数据源 <!-- 使用c3p0数据库连接池时 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.cj.jdbc.Driver" /> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring?useSSL=false" /> <property name="user" value="root" /> <property name="password" value="123" /> </bean> <!-- 使用Spring内置数据源 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driverClass}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- 使用外部配置文件的Spring内置数据源时 --> <!-- 引入外部配置文件 --> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:jdbc.properties"></property> </bean> <!-- 使用注解引入外部文件时 --> <context:property-placeholder location="classpath:jdbc.properties"/>

2. 使用JdbcTemplate实现增删改查操作

在配置文件中配置JdbcTemplate <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource" /> </bean> 可以直接使用JdbcTemplate实现增删改查操作

3. 在Dao中使用JdbcTemplate

不通过继承JdbcDaoSupport来简化获取JdbcTemplate的操作(用于xml配置和注解配置中) 在Dao实现类中添加jdbcTemplate属性 private JdbcTemplate jdbcTemplate; // 添加注入 public void setJdbcTemplate(JdbcTemplate jdbcTemplate){ this.jdbcTemplate = jdbcTemplate; } 在配置文件中添加Dao实现类的bean <bean id="accountDao" class="...AccountDaoImpl"> <property name="jdbcTemplate" ref="jdbcTemplate" /> </bean> 使用jdbcTemplate属性执行数据库操作 通过继承JdbcDaoSupport来简化获取JdbcTemplate的操作(仅限于xml配置中) 在Dao实体类中继承JdbcDaoSupport,不用添加jdbcTemplate属性 public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { } 在配置文件中添加Dao实体类的Bean <bean id="accountDao" class="..AccountDaoImpl"> <!-- 可以配置JdbcTemplate也可以配置DataSource 配置一个即可--> <!-- 配置JdbcTempldate --> <property name="jdbcTemplate" ref="jdbcTemplate" /> <!-- 配置DataSource --> <property name="dataSource" ref="dataSource" /> </bean> 调用父类的方法super.getJdbcTemplate()来执行相应的数据库操作

7. Spring中的事务控制

Spring中关于事务控制的API

1. PlatformTransactionManager(Spring中的事务管理器)

PlatformTransactionManager接口提供了事务操作的方法,其中包含3各具体的操作:

获取事务状态信息TransactionStatus getTransaction(TransactionDefinition definition) 提交事务void commit(TransactionStatus status) 回滚事务void rollback(TransactionStatus status) 真正使用的是PlatformTransactionManager接口的实体类:org.springframework.jdbc.datasource.==DataSourceTransactionManager== 使用Spring JDBC或iBatis进行持久化数据时使用org.springframework.orm.hibernate5.==HibernateTransactionManager== 使用Hibernate版本进行持久化数据时使用

2. TransactionDefinition

TransactionDefinition是事务的信息定义对象,方法如下:

获取事务对象名称:String getName() 获取事务隔离级别:int getIsolationLevel() 默认级别,归属以下某一种:ISOLATION_DEFAULT 可以读取未提交数据:ISOLATION_READ_UNCOMMITTED 只能读取已提交数据,解决脏读问题(Oracle默认级别):ISOLATION_READ_COMMITTED 是否读取其他事务提交修改后的数据,解决不可重复读问题(MySql默认级别):ISOLATION_REPEATABLE_READ 是否读取其他事务提交添加后的数据,解决幻影读的问题:ISOLATION_SERIALIZABLE 获取事务传播途径:int getPropagationBehavior() REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到该事务中。(默认值) SUPPORTS:支持当前事务,如果当前没有事务,就通过非事务方式执行MANDATORY:使用当前的事务,如果当前没有事务则抛异常REQUERS_NEW:新建事务,如果当前在事务中,则将当前事务挂起NOT_SUPPORTED:以非事务的方式执行操作,如果当前存在事务,则将当前事务挂起NEVER:以非事务的方式运行,如果当前存在事务,抛出异常NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行REQUIRED类似的操作 获取事务超时时间:int getTimeout() 默认值为-1,没有超时限制。如果有则以秒为单位进行设置 获取事务是否只读:boolean isReadOnly() 只读事务:查询读写型事务:增删改

3. TransactionStatus

TransactionStatus接口提供某个时间点上事务对象的状态信息,其中有6个具体的操作

刷新事务:void flush() 获取是否存在存储点:boolean hasSavepoint() 获取事务是否完成:boolean isCompleted() 获取事务是否为新的事务:boolean isNewTransaction() 获取事务是否回滚:boolean isRollbackOnly() 设置事务回滚:void setRollbackOnly()

Spring中事务控制的具体操作

1. 导入Spring事务控制的相关坐标

<!-- JDBC相关坐标 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!-- 事务控制相关坐标 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.0.2.RELEASE</version> </dependency>

2. 在配置文件中导入aop和tx约束

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd"> </beans>

3. 配置Bean、数据源、事务控制、AOP

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd"> <!-- 配置service --> <bean id="accountService" class="com.hsh.study.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean> <!-- 配置DAO --> <bean id="accountDao" class="com.hsh.study.dao.impl.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置数据源 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.classDriver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- 配置数据库配置文件 --> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:jdbc.properties" /> </bean> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 导入数据源 --> <property name="dataSource" ref="dataSource" /> </bean> <!-- 事务的配置 --> <tx:advice id="txAdvice" transaction-manager="transactionManager" > <!-- 配置事务的属性 --> <tx:attributes> <tx:method name="*" read-only="false" propagation="REQUIRED"/> <tx:method name="find*" read-only="true" propagation="SUPPORTS"/> </tx:attributes> </tx:advice> <!-- AOP的配置 --> <aop:config> <!-- 配置切入点表达式 --> <aop:pointcut id="pt1" expression="execution(* com.hsh.study.service.impl.*.*(..))"/> <!-- 配置AOP --> <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"></aop:advisor> </aop:config> </beans>

Spring中事务控制的具体操作(使用注解开发)

主注解类的配置 // 声明式配置类 @Configuration // 告诉Spring要扫描的包 @ComponentScan("com.hsh.study") // 导入的另一个配置类 @Import(JdbcConfig.class) // 配置文件的声明 @PropertySource("classpath:jdbc.properties") // 开启注解AOP支持 @EnableAspectJAutoProxy // 开启注解事务支持 @EnableTransactionManagement public class SpringConfig { } Jdbc注解类的配置 public class JdbcConfig { // @Value:表示引入配置文件中的值 @Value("${jdbc.classDriver}") private String classDriver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; // 声明jdbcTemplate @Bean("jdbcTemplate") public JdbcTemplate createJdbcTemplate(DataSource dataSource){ return new JdbcTemplate(dataSource); } /** * 创建事务管理器 * Bean注解不配值时,默认类名首字母小写如DataSourceTransactionManager变成dataSourceTransactionManager */ @Bean public DataSourceTransactionManager transactionManager(DataSource dataSource){ return new DataSourceTransactionManager(dataSource); } // 声明数据源 @Bean("dataSource") public DataSource createDataSource(){ try { DriverManagerDataSource manager = new DriverManagerDataSource(); manager.setDriverClassName(classDriver); manager.setUrl(url); manager.setUsername(username); manager.setPassword(password); return manager; } catch (Exception e) { throw new RuntimeException(e); } } } 业务层实现 @Service("accountService") @Transactional(readOnly = true,propagation = Propagation.SUPPORTS) public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; @Override @Transactional(readOnly = false,propagation = Propagation.REQUIRED) public void transfer(String sourceName, String targetName, Double money) { // 获取两个用户 Account source = accountDao.findByName(sourceName); Account target = accountDao.findByName(targetName); // 执行转账操作 source.setMoney(source.getMoney()-money); target.setMoney(target.getMoney()+money); // 执行更新操作 accountDao.update(source); accountDao.update(target); } 持久层实现 @Repository("accountDao") public class AccountDaoImpl implements AccountDao { @Autowired private JdbcTemplate jdbcTemplate; @Override public Account findById(Integer accountId) { List<Account> accounts = jdbcTemplate.query("select * from account where id = ?", new BeanPropertyRowMapper<Account>(Account.class), accountId); return accounts.isEmpty()?null:accounts.get(0); } @Override public Account findByName(String accountName) { List<Account> accounts = jdbcTemplate.query("select * from account where name = ?", new BeanPropertyRowMapper<Account>(Account.class), accountName); if (accounts.isEmpty()){ return null; } if (accounts.size() > 1){ throw new RuntimeException("结果集不唯一"); } return accounts.get(0); } @Override public void update(Account account) { jdbcTemplate.update("update account set money = ? where id = ?", account.getMoney(),account.getId()); } }
最新回复(0)