Spring 是一个开源的轻量级 JavaEE(现在称为 Jakarta EE)开发框架,用于构建企业级应用程序和分布式系统。它提供了一种简化和解耦应用程序组件的方式,使开发人员能够更加专注于业务逻辑的实现,而不需要过多关心底层的技术细节。Spring 框架包含多个模块,每个模块提供不同的功能,如依赖注入、面向切面编程、事务管理、Web 开发等。
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.3.10version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13.2version>
<scope>testscope>
dependency>
dependencies>
package com.acaiblog.spring.pojo;
public class User {
private Integer id;
private String name;
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
<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="user" class="com.acaiblog.spring.pojo.User">
<property name="id" value="1"/>
<property name="name" value="acai"/>
bean>
beans>
import com.acaiblog.spring.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring {
@Test
public void test(){
// 创建容器对象
ApplicationContext aplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取配置bean
User user = aplicationContext.getBean("user", User.class);
System.out.println(user);
}
}
User{id=1, name='acai'}
getBean(String beanId)
:通过beanId获取对象;缺点:需要强制类型转换,不灵活。getBean(Class clazz)
:通过Class对象获取对象;缺点:容器中有多个bean会报错getBean(String beanId,Class clazz)
:通过beanId和Class对象在Spring Framework中,“bean” 是一个核心概念,用于定义应用程序中的各种组件、对象或服务。Spring的IoC(Inversion of Control,控制反转)容器负责管理和实例化这些bean。在XML配置文件中,使用标签来定义和配置这些bean。
Bean标签属性
属性 | 描述 |
---|---|
id | 表示bean的唯一标识符,应该在整个Spring上下文中是唯一的。 |
class | 指定bean的全限定类名,用于告诉Spring容器应该实例化哪个类来创建bean对象。 |
scope | 定义bean的作用域,常用的有singleton(单例,默认)、prototype(原型)、request、session等。例如:scope="singleton" 。 |
init-method | 指定在bean初始化之后调用的方法。 |
destroy-method | 指定在bean销毁之前调用的方法。 |
Bean子标签property属性
property主要是用来给类对象方法注入参数
属性 | 描述 |
---|---|
name | 指定bean的属性名。 |
value | 设置基本数据类型的属性值。 |
ref | 引用其他bean作为属性值。 |
Bean子标签constructor-arg属性
constructor-arg标签主要是用来给构造器注入参数
属性名称 | 描述 |
---|---|
index | 构造函数参数的索引(从0开始)。 |
type | 参数的数据类型。 |
value | 参数的值,可以是字符串、基本类型或引用。 |
ref | 参数的引用,指向另一个bean的id。 |
name | 参数的名称,用于指定构造函数的参数名。 |
语法
<bean id="user" class="com.acaiblog.spring.pojo.User">
<property name="id" value="1"/>
<property name="name" value="acai"/>
bean>
<bean id="user" class="com.acaiblog.spring.pojo.User">
<constructor-arg name="id" value="2"/>
<constructor-arg name="name" value="acai"/>
bean>
<bean id="user"
class="com.acaiblog.spring.pojo.User"
p:id="1"
p:name="acaiblog">
bean>
如果想通过查询员工信息的同时获取员工所在部门信息就需要使用外部已声明bean
package com.acaiblog.spring.pojo;
public class Employee {
private Integer id;
private String name;
private String email;
private Dept dept;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
", dept=" + dept +
'}';
}
}
package com.acaiblog.spring.pojo;
public class Dept {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Dept{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
<bean id="dept1" class="com.acaiblog.spring.pojo.Dept">
<property name="id" value="1"/>
<property name="name" value="运维部"/>
bean>
<bean id="employee" class="com.acaiblog.spring.pojo.Employee">
<property name="id" value="1"/>
<property name="name" value="acai"/>
<property name="email" value="[email protected]"/>
<property name="dept" ref="dept1"/>
bean>
import com.acaiblog.spring.pojo.Employee;
import com.acaiblog.spring.pojo.User;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring {
@Test
public void test(){
// 创建容器对象
ApplicationContext aplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取配置bean
Employee employee = aplicationContext.getBean("employee", Employee.class);
System.out.println(employee);
}
}
Employee{id=1, name='acai', email='[email protected]', dept=Dept{id=1, name='运维部'}}
<bean id="dept1" class="com.acaiblog.spring.pojo.Dept">
<property name="id" value="1"/>
<property name="name" value="运维部"/>
bean>
<bean id="employee" class="com.acaiblog.spring.pojo.Employee">
<property name="id" value="1"/>
<property name="name" value="acai"/>
<property name="email" value="[email protected]"/>
<property name="dept" ref="dept1"/>
<property name="dept.name" value="测试部"/>
bean>
内部bean不会覆盖外部bean的属性值
<bean id="employee" class="com.acaiblog.spring.pojo.Employee">
<property name="id" value="1"/>
<property name="name" value="acai"/>
<property name="email" value="[email protected]"/>
<property name="dept">
<bean class="com.acaiblog.spring.pojo.Dept">
<property name="id" value="2"/>
<property name="name" value="研发部"/>
bean>
property>
bean>
需求
比如云计算事业部,有两个员工。使用List集合的方式展示数据
public class Dept {
private List<Employee> employeeList;
public List<Employee> getEmployeeList() {
return employeeList;
}
public void setEmployeeList(List<Employee> employeeList) {
this.employeeList = employeeList;
}
@Override
public String toString() {
return "Dept{" +
"id=" + id +
", name='" + name + '\'' +
", employeeList=" + employeeList +
'}';
}
}
<bean id="zhangsan" class="com.acaiblog.spring.pojo.Employee">
<property name="id" value="1"/>
<property name="name" value="zhangsan"/>
<property name="email" value="[email protected]"/>
bean>
<bean id="lisi" class="com.acaiblog.spring.pojo.Employee">
<property name="id" value="2"/>
<property name="name" value="lisi"/>
<property name="email" value="[email protected]"/>
bean>
<bean id="dept" class="com.acaiblog.spring.pojo.Dept">
<property name="id" value="1"/>
<property name="name" value="云计算事业部"/>
<property name="employeeList">
<list>
<ref bean="zhangsan"/>
<ref bean="lisi"/>
list>
property>
bean>
public class TestSpring {
@Test
public void test(){
// 创建容器对象
ApplicationContext aplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取配置bean
Dept dept = aplicationContext.getBean("dept", Dept.class);
System.out.println(dept);
}
}
Dept{id=1, name='云计算事业部', employeeList=[Employee{id=1, name='zhangsan', email='[email protected]', dept=null, empList=null}, Employee{id=2, name='lisi', email='[email protected]', dept=null, empList=null}]}
public class Dept {
private Map<String, Employee> employeeMap;
public Map<String, Employee> getEmployeeMap() {
return employeeMap;
}
public void setEmployeeMap(Map<String, Employee> employeeMap) {
this.employeeMap = employeeMap;
}
@Override
public String toString() {
return "Dept{" +
"id=" + id +
", name='" + name + '\'' +
", employeeList=" + employeeList +
", employeeMap=" + employeeMap +
'}';
}
}
<bean id="zhangsan" class="com.acaiblog.spring.pojo.Employee">
<property name="id" value="1"/>
<property name="name" value="zhangsan"/>
<property name="email" value="[email protected]"/>
bean>
<bean id="lisi" class="com.acaiblog.spring.pojo.Employee">
<property name="id" value="2"/>
<property name="name" value="lisi"/>
<property name="email" value="[email protected]"/>
bean>
<bean id="dept" class="com.acaiblog.spring.pojo.Dept">
<property name="id" value="1"/>
<property name="name" value="云计算事业部"/>
<property name="employeeMap">
<map>
<entry>
<key><value>111value>key>
<ref bean="zhangsan"/>
entry>
<entry>
<key><value>222value>key>
<ref bean="lisi"/>
entry>
map>
property>
bean>
public class TestSpring {
@Test
public void test(){
// 创建容器对象
ApplicationContext aplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取配置bean
Dept dept = aplicationContext.getBean("dept", Dept.class);
System.out.println(dept);
}
}
Dept{id=1, name='云计算事业部', employeeList=null, employeeMap={111=Employee{id=1, name='zhangsan', email='[email protected]', dept=null, empList=null}, 222=Employee{id=2, name='lisi', email='[email protected]', dept=null, empList=null}}}
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.2.18version>
dependency>
<dependency>
<groupId>org.mariadb.jdbcgroupId>
<artifactId>mariadb-java-clientartifactId>
<version>3.1.4version>
dependency>
#db.properties
db.driver=org.mariadb.jdbc.Driver
db.url=jdbc:mariadb://acaiblog.top:3306/spring
db.username=root
db.password=123456
<context:property-placeholder location="classpath:db.properties">context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
bean>
public class TestSpring {
@Test
public void test() throws Exception{
// 创建容器对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取bean
DruidDataSource druidDataSource = applicationContext.getBean("dataSource", DruidDataSource.class);
// 连接数据库对象
DruidPooledConnection druidPooledConnection = druidDataSource.getConnection();
System.out.println(druidPooledConnection);
}
}
FactoryBean 是 Spring 框架中的一个接口,用于创建和管理 Spring 容器中的对象。它允许开发人员在创建 bean 实例时进行更加灵活和自定义的操作。通过实现 FactoryBean 接口,您可以控制 bean 的实例化、初始化和销毁过程,以及对外暴露的对象类型。
内置方法
方法 | 描述 |
---|---|
getObject() |
实际创建和返回 bean 实例,可以执行自定义逻辑,如从外部资源加载数据、实例化其他对象等。 |
getObjectType() |
返回由 FactoryBean 创建的对象的类型,通常用于告诉 Spring 容器实际创建的 bean 类型。 |
isSingleton() |
返回一个布尔值,指示由 FactoryBean 创建的对象是否是单例(singleton)或原型(prototype)。 |
实现步骤
package com.acaiblog.spring.Factory;
import com.acaiblog.spring.pojo.Dept;
import org.springframework.beans.factory.FactoryBean;
public class MyFactoryBean implements FactoryBean<Dept> {
@Override
public boolean isSingleton() {
/**设置参数是否为单例*/
return FactoryBean.super.isSingleton();
}
@Override
public Dept getObject() throws Exception {
/**参数对象创建的方法,比如:创建一个部门然后将部门返回*/
Dept dept = new Dept(1,"运维部");
return dept;
}
@Override
public Class<?> getObjectType() {
/**设置参数对象class*/
return Dept.class;
}
}
<bean id="factoryBean" class="com.acaiblog.spring.Factory.MyFactoryBean">
public class TestSpring {
@Test
public void test() throws Exception{
// 创建容器对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取bean
Dept dept = applicationContext.getBean("factoryBean", Dept.class);
System.out.println(dept);
}
}
Dept{id=1, name='运维部', employeeList=null, employeeMap=null}
语法
在 Spring 配置文件中使用 标签的 scope 属性来显式指定 Bean 的作用域。例如:
<bean id="myBean" class="com.example.MyBean" scope="prototype"/>
作用域
作用域 | 描述 |
---|---|
singleton | 每个 Spring 容器中只会存在一个单例的 Bean 实例。在应用程序生命周期内,只会创建一个 Bean 实例并缓存以供后续使用。 |
prototype | 每次请求该 Bean 时,都会创建一个新的实例。不同地方请求该 Bean 会得到不同的实例。 |
request | 在 Web 应用中有效,每个 HTTP 请求都会创建一个新的 Bean 实例,在整个请求周期内有效。不同请求间可对应不同的实例。 |
session | 在 Web 应用中有效,每个用户会话(Session)都会创建一个新的 Bean 实例,在整个会话周期内有效。不同用户对应不同的实例。 |
application | 在 Web 应用中有效,每个 ServletContext(Web 应用上下文)都会创建一个新的 Bean 实例,在整个应用生命周期内有效。 |
websocket | 在 Web 应用中有效,每个 WebSocket 会话都会创建一个新的 Bean 实例,在整个 WebSocket 会话周期内有效。 |
custom | 您可以实现自定义的作用域,通过实现 org.springframework.beans.factory.config.Scope 接口来定义更灵活的作用域。 |
在Spring框架中,Bean的生命周期是指一个Bean从被创建到被销毁的整个过程。Spring框架提供了丰富的生命周期回调方法,可以让开发者在不同的阶段进行自定义操作。
BeanFactory接口描述
接口名称 | 特点 |
---|---|
ConfigurableApplicationContext | 可配置和修改应用程序上下文,包含刷新和关闭方法。 |
ApplicationContext | 提供核心功能的只读应用程序上下文,无法在运行时修改或重新配置。 |
生命周期步骤
package com.acaiblog.spring.pojo;
public class Student {
private Integer id;
private String name;
public void Init(){
System.out.println("初始化方法");
}
public void Destory(){
System.out.println("销毁方法");
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
<bean id="student" class="com.acaiblog.spring.pojo.Student" init-method="Init" destroy-method="Destory">
<property name="id" value="1"/>
<property name="name" value="慕容峻才"/>
bean>
public class TestSpring {
@Test
public void test() throws Exception{
// 创建容器对象使用ConfigurableApplicationContext可以关闭容器,用来自动调用销毁方法
ConfigurableApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取bean
Student student = applicationContext.getBean("student", Student.class);
System.out.println(student);
// 调用Bean中定义的destroy-method方法
applicationContext.close();
}
}
初始化方法
Student{id=1, name='慕容峻才'}
销毁方法
作用
在初始化前后对bean进行额外的处理
实现步骤
package com.acaiblog.spring.processor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
/**
* Bean初始化之前执行
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean初始化之前执行");
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
/**
* Bean初始化之后会执行
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean初始化之后执行");
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" 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 https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="student" class="com.acaiblog.spring.pojo.Student" init-method="Init" destroy-method="Destory">
<property name="id" value="1"/>
<property name="name" value="慕容峻才"/>
bean>
<bean class="com.acaiblog.spring.processor.MyBeanPostProcessor"/>
beans>
根据bean标签的autowire属性指定装配规则,不需要明确指定。Spring自动将匹配的属性值注入bean中。autowire属性值如下表:
属性名 | 描述 |
---|---|
byName | 按组件名称自动装配 |
byType | 按组件类型自动装配 |
constructor | 通过构造函数自动装配 |
package com.acaiblog.spring.dao;
import com.acaiblog.spring.pojo.Dept;
public interface DeptDao {
/**
* 添加部门信息
* @param dept
*/
public void insertDept(Dept dept);
}
package com.acaiblog.spring.dao.Impl;
import com.acaiblog.spring.dao.DeptDao;
import com.acaiblog.spring.pojo.Dept;
public class DeptDaoImpl implements DeptDao {
@Override
public void insertDept(Dept dept) {
System.out.println("添加部门成功");
}
}
package com.acaiblog.spring.service;
import com.acaiblog.spring.pojo.Dept;
public interface DeptService {
/**
* 添加部门信息
* @param dept
*/
public void save(Dept dept);
}
package com.acaiblog.spring.service.Impl;
import com.acaiblog.spring.dao.DeptDao;
import com.acaiblog.spring.pojo.Dept;
import com.acaiblog.spring.service.DeptService;
public class DeptServiceImpl implements DeptService {
private DeptDao deptDao;
@Override
public void save(Dept dept) {
deptDao.insertDept(dept);
}
}
public class TestSpring {
@Test
public void test() throws Exception{
// 创建容器对象使用ConfigurableApplicationContext可以关闭容器,用来自动调用销毁方法
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
// 获取bean
DeptService deptService = applicationContext.getBean("deptService", DeptService.class);
deptService.saveDept(new Dept());
}
}
对象中属性与容器中的beanId进行匹配,如果属性名和beanId匹配成功则自动装配成功
<bean id="deptDao" class="com.acaiblog.spring.dao.Impl.DeptDaoImpl">bean>
<bean id="deptService" class="com.acaiblog.spring.service.Impl.DeptServiceImpl" autowire="byName">bean>
对象中的属性类型与容器中bean的class进行匹配,如果唯一匹配则自动装配成功
<bean id="deptDao" class="com.acaiblog.spring.dao.Impl.DeptDaoImpl">bean>
<bean id="deptService" class="com.acaiblog.spring.service.Impl.DeptServiceImpl" autowire="byType">bean>
创建spring工程day07_spring导入spring相关依赖包
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.3.10version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13.2version>
<scope>testscope>
dependency>
dependencies>
创建Employee pojo
package com.acaiblog.spring.pojo;
import java.util.List;
public class Employee {
private Integer id;
private String name;
private String email;
private Dept dept;
private List<Employee> empList;
public List<Employee> getEmpList() {
return empList;
}
public void setEmpList(List<Employee> empList) {
this.empList = empList;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
", dept=" + dept +
", empList=" + empList +
'}';
}
}
创建dept pojo
package com.acaiblog.spring.pojo;
import java.util.List;
import java.util.Map;
public class Dept {
private Integer id;
private String name;
private List<Employee> employeeList;
private Map<String, Employee> employeeMap;
@Override
public String toString() {
return "Dept{" +
"id=" + id +
", name='" + name + '\'' +
", employeeList=" + employeeList +
", employeeMap=" + employeeMap +
'}';
}
public Map<String, Employee> getEmployeeMap() {
return employeeMap;
}
public void setEmployeeMap(Map<String, Employee> employeeMap) {
this.employeeMap = employeeMap;
}
public List<Employee> getEmployeeList() {
return employeeList;
}
public void setEmployeeList(List<Employee> employeeList) {
this.employeeList = employeeList;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
创建Dept接口
package com.acaiblog.spring.dao;
import com.acaiblog.spring.pojo.Dept;
public interface DeptDao {
/*
* 新增部门信息*/
public void insertDept(Dept dept);
}
创建DeptDaoImpl
package com.acaiblog.spring.dao.impI;
import com.acaiblog.spring.dao.DeptDao;
import com.acaiblog.spring.pojo.Dept;
public class DeptDaoImpl implements DeptDao {
@Override
public void insertDept(Dept dept) {
System.out.println("添加部门成功");
}
}
创建DeptService
package com.acaiblog.spring.service;
import com.acaiblog.spring.pojo.Dept;
public interface DeptService {
/*
* 添加部门*/
public void saveDept(Dept dept);
}
创建DeptServiceImpl
package com.acaiblog.spring.service.impl;
import com.acaiblog.spring.dao.DeptDao;
import com.acaiblog.spring.pojo.Dept;
import com.acaiblog.spring.service.DeptService;
public class DeptServiceImpl implements DeptService {
private DeptDao deptDao;
@Override
public void saveDept(Dept dept) {
deptDao.insertDept(dept);
}
}
创建DeptController
package com.acaiblog.spring.controller;
import com.acaiblog.spring.pojo.Dept;
import com.acaiblog.spring.service.DeptService;
public class DeptController {
private DeptService deptService;
public void saveDept(){
deptService.saveDept(new Dept());
}
}
创建spring配置文件
<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="deptDao" class="com.acaiblog.spring.dao.impI.DeptDaoImpl">bean>
beans>
创建测试代码,验证环境没有问题
import com.acaiblog.spring.dao.impI.DeptDaoImpl;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
DeptDaoImpl deptDao = context.getBean("deptDao", DeptDaoImpl.class);
System.out.println("deptDao:" + deptDao);
}
}
注解的位置: 在类的上面标识
使用注解装配:默认将类名首字母小写作为bean id;可以使用value属性为类的bean id指定id;当注解中只使用一个value属性时,value关键字可以省略
使用注解的步骤:导入相关jar包,spring默认已经导入;开启组件扫描;使用注解标识组件
注解 | 描述 |
---|---|
@Autowired |
自动装配依赖关系。 |
@Component |
通用的Spring组件注解。 |
@Controller |
标识控制器类。 |
@Service |
标识服务类。 |
@Repository |
标识数据访问对象(DAO)类。 |
package com.acaiblog.spring.dao.impI;
import com.acaiblog.spring.dao.DeptDao;
import com.acaiblog.spring.pojo.Dept;
import org.springframework.stereotype.Repository;
@Repository("deptDao")
public class DeptDaoImpl implements DeptDao {
@Override
public void insertDept(Dept dept) {
System.out.println("添加部门成功");
}
}
package com.acaiblog.spring.pojo;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
@Component
public class Dept {
}
package com.acaiblog.spring.service.impl;
import com.acaiblog.spring.dao.DeptDao;
import com.acaiblog.spring.pojo.Dept;
import com.acaiblog.spring.service.DeptService;
import org.springframework.stereotype.Service;
@Service
public class DeptServiceImpl implements DeptService {
private DeptDao deptDao;
@Override
public void saveDept(Dept dept) {
deptDao.insertDept(dept);
}
}
package com.acaiblog.spring.controller;
import com.acaiblog.spring.pojo.Dept;
import com.acaiblog.spring.service.DeptService;
import org.springframework.stereotype.Controller;
@Controller
public class DeptController {
private DeptService deptService;
public void saveDept(){
deptService.saveDept(new Dept());
}
}
<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 https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.acaiblog.spring">context:component-scan>
beans>
import com.acaiblog.spring.controller.DeptController;
import com.acaiblog.spring.dao.impI.DeptDaoImpl;
import com.acaiblog.spring.pojo.Dept;
import com.acaiblog.spring.service.impl.DeptServiceImpl;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
Dept dept = context.getBean("dept", Dept.class);
DeptDaoImpl deptDao = context.getBean("deptDao", DeptDaoImpl.class);
DeptServiceImpl deptService = context.getBean("deptServiceImpl", DeptServiceImpl.class);
DeptController deptController = context.getBean("deptController", DeptController.class);
System.out.println("dept:" + dept);
System.out.println("deptDao:" + deptDao);
System.out.println("deptService:" + deptService);
System.out.println("deptController:" + deptController);
}
}
[自动装配]
@Autowired注解作用:自动装配对象中的属性
@Autowired注解装配原理:反射机制
@Autowired注解装配方式:先byType匹配,如果匹配0个返回错误;如果匹配1个正常允许;如果匹配多个再按照byName进行唯一筛选匹配,筛选成功对象中的属性名称等同于beanId,筛选是吧对象中的属性名称比等于beanId。
@Autowired注解required属性为true,表示被标识的属性必须装配数值,如未装配会报错;属性为false,表示被标识的属性必须装配属性,如未装配不会报错。
实现步骤
添加注解
package com.acaiblog.spring.service.impl;
import com.acaiblog.spring.dao.DeptDao;
import com.acaiblog.spring.pojo.Dept;
import com.acaiblog.spring.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptDao deptDao;
@Override
public void saveDept(Dept dept) {
deptDao.insertDept(dept);
}
}
测试代码
import com.acaiblog.spring.pojo.Dept;
import com.acaiblog.spring.service.DeptService;
import com.acaiblog.spring.service.impl.DeptServiceImpl;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
DeptService deptService = context.getBean("deptServiceImpl", DeptServiceImpl.class);
deptService.saveDept(new Dept());
}
}
测试结果
添加部门成功
@Qualifier和@Autowired配合使用,将设置的beanId名称装配到对象属性中。
扫描包下所有子包
<context:component-scan base-package="com.acaiblog.spring">context:component-scan>
扫描指定的多个包
<context:component-scan base-package="com.acaiblog.aaa,com.acaiblog.bbb">context:component-scan>
包含扫描
<context:component-scan base-package="com.acaiblog.spring" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
<context:include-filter type="assignable" expression="com.acaiblog.spring.service.impl.DeptServiceImpl"/>
context:component-scan>
排除扫描
<context:component-scan base-package="com.acaiblog.spring">
<context:exclude-filter type="assignable" expression="org.springframework.stereotype.Controller"/>
context:component-scan>
@Configuration 将该注解的类代替xml配置文件
@ComponentSan 配置要扫描的包
创建配置类,在类上面添加注解
package com.acaiblog.spring.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = "com.acaiblog.spring")
public class SpringConfig {
}
使用AnnotationConfigApplicationContext容器对象
import com.acaiblog.spring.config.SpringConfig;
import com.acaiblog.spring.pojo.Dept;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class TestSpring {
@Test
public void test(){
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
Dept dept = context.getBean("dept", Dept.class);
System.out.println("dept: "+ dept);
}
}
测试结果
dept: Dept{id=null, name='null', employeeList=null, employeeMap=null}
导入jar包
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>5.3.10version>
<scope>testscope>
dependency>
指定Spring配置文件路径和Spring环境下运行Junit4的运行器
import com.acaiblog.spring.pojo.Dept;
import com.acaiblog.spring.service.DeptService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@ContextConfiguration(locations = "classpath:application.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringJunit4Test {
@Autowired
private DeptService deptService;
@Test
public void test(){
deptService.saveDept(new Dept());
}
}
AOP概述
AOP:Aspect-Oriented Programming,面向切面编程;是对OOP(Object-Oriented Programming,面向对象编程)的一种扩展,是一种通过动态代理实现程序功能扩展和统一维护的技术。
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提供程序的可重用行,同时提高了开发的效率。
AOP专业术语
AspectJ是java社区里最完整的AOP框架,在Spring2.0以上版本中可以使用基于AspectJ注解或基于xml配置的AOP。
语法
@Before(value = "execution(权限修饰符 返回值类型 包名.类名.方法(参数类型))")
通配符
通配符 | 描述 |
---|---|
* |
可以代表任意权限修饰符和返回值类型,可以代表任意包名、类名、方法名 |
.. |
代表任意参数类型及参数个数 |
重用切入点表达式
使用@PointCut注解,提取可重用的切入点表达式
@PointCut("execution(* com.acaiblog.aop.CalcImpl.*(..))")
public vold MyPoint(){}
使用方法名引入切入点表达式:
@Before(value = "MyPoint()")
public vold BeforeMethod(JoinPoint joinPoint){}
作用
joinPoint.getSignature().getName();
joinPoint.getArgs();
前置通知
语法:@Before
执行时机:指定方法执行之前执行,指定方法是切入点表达式设置位置
后置通知
语法:@After
执行时机:指定方法执行之后执行
返回通知
语法:@AfterReturning
执行时机:指定方法返回结果时执行
注意事项:@AfterReturning中的returning属性与方法入参参数名一致
异常通知
语法:@AfterThrowing
执行时机:指定方法出现异常时执行
环绕通知
语法:@Around
作用:整合前面4个通知
注意:参数中必须使用ProceedingJoinPoint
语法:@Oder(value=index),index是int类型,默认值是int可存储的最大值;数值越小优先级越高
pom.xml添加jar包
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.3.10version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13.2version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>5.3.10version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>5.3.10version>
dependency>
dependencies>
编写applicationContext.xml配置文件
<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">
<context:component-scan base-package="com.acaiblog.aop">context:component-scan>
<aop:aspectj-autoproxy>aop:aspectj-autoproxy>
beans>
在MyLogging中配置切面类
package com.acaiblog.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Component
@Aspect
public class MyLogging {
@Before(value = "execution(public int add(int,int))")
public static void beforeMethod(JoinPoint joinPoint){
// 获取方法名称
String methodName = joinPoint.getSignature().getName();
// 获取参数
Object[] args = joinPoint.getArgs();
System.out.println("Calc:" + methodName + "方法,参数:" + Arrays.toString(args));
}
public static void afterMethod(String methodName, Object[] args){
System.out.println("Calc:" + methodName + "方法,参数:" + Arrays.toString(args));
}
}
什么是JDBCTemplate
JDBCTemplate是一个Spring提供的小型持久化框架,简化jdbc的代码。
pom.xml导入jar包
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.3.10version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-ormartifactId>
<version>5.3.10version>
dependency>
<dependency>
<groupId>org.mariadb.jdbcgroupId>
<artifactId>mariadb-java-clientartifactId>
<version>3.1.4version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.2.19version>
dependency>
dependencies>
resource下创建db配置文件db.properties
db.driver=org.mariadb.jdbc.Driver
db.url=jdbc:mariadb://127.0.0.1:3306/jdbc
db.username=root
db.password=123
resource下创建spring配置文件application.xml
<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:property-placeholder location="classpath:db.properties">context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
bean>
beans>
编写测试类
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
public class TestSpringJDBCTemplate {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
JdbcTemplate jdbcTemplate = context.getBean("jdbcTemplate", JdbcTemplate.class);
System.out.println(jdbcTemplate);
}
}
增加
方法 | 描述 |
---|---|
update(String sql) |
执行给定的 SQL 更新语句,返回受影响的行数。 |
update(String sql, Object... args) |
执行带参数的 SQL 更新语句,返回受影响的行数。 |
update(String sql, SqlParameterSource paramSource) |
执行带参数的 SQL 更新语句,返回受影响的行数。 |
batchUpdate(String sql, BatchPreparedStatementSetter pss) |
批量执行带参数的 SQL 更新语句,每个更新语句在事务中执行。 |
batchUpdate(String sql, Map |
批量执行带参数的 SQL 更新语句,每个更新语句在事务中执行。 |
删除
方法 | 描述 |
---|---|
update(String sql) |
执行给定的 SQL 更新语句,返回受影响的行数。 |
update(String sql, Object... args) |
执行带参数的 SQL 更新语句,返回受影响的行数。 |
update(String sql, SqlParameterSource paramSource) |
执行带参数的 SQL 更新语句,返回受影响的行数。 |
batchUpdate(String sql, BatchPreparedStatementSetter pss) |
批量执行带参数的 SQL 更新语句,每个更新语句在事务中执行。 |
batchUpdate(String sql, Map |
批量执行带参数的 SQL 更新语句,每个更新语句在事务中执行。 |
修改
方法 | 描述 |
---|---|
update(String sql) |
执行给定的 SQL 更新语句,返回受影响的行数。 |
update(String sql, Object... args) |
执行带参数的 SQL 更新语句,返回受影响的行数。 |
update(String sql, SqlParameterSource paramSource) |
执行带参数的 SQL 更新语句,返回受影响的行数。 |
batchUpdate(String sql, BatchPreparedStatementSetter pss) |
批量执行带参数的 SQL 更新语句,每个更新语句在事务中执行。 |
batchUpdate(String sql, Map |
批量执行带参数的 SQL 更新语句,每个更新语句在事务中执行。 |
查询
方法 | 描述 |
---|---|
query(String sql, RowMapper |
执行给定的 SQL 查询语句,将结果映射为对象列表。 |
queryForObject(String sql, Class |
执行给定的 SQL 查询语句,返回单个结果对象。 |
queryForList(String sql) |
执行给定的 SQL 查询语句,返回结果列表。 |
queryForMap(String sql) |
执行给定的 SQL 查询语句,将结果映射为键值对。 |
queryForList(String sql, Class |
执行给定的 SQL 查询语句,将结果映射为指定类型的对象列表。 |
queryForMap(String sql, Object... args) |
执行带参数的 SQL 查询语句,将结果映射为键值对。 |
queryForObject(String sql, Class |
执行带参数的 SQL 查询语句,返回单个结果对象。 |
queryForList(String sql, Object... args) |
执行带参数的 SQL 查询语句,返回结果列表。 |
query(String sql, RowMapper |
执行带参数的 SQL 查询语句,将结果映射为对象列表。 |
queryForMap(String sql, SqlParameterSource paramSource) |
执行带参数的 SQL 查询语句,将结果映射为键值对。 |
queryForObject(String sql, SqlParameterSource paramSource, Class |
执行带参数的 SQL 查询语句,返回单个结果对象。 |
queryForList(String sql, SqlParameterSource paramSource) |
执行带参数的 SQL 查询语句,返回结果列表。 |
query(String sql, RowMapper |
执行带参数的 SQL 查询语句,将结果映射为对象列表。 |
create table dept(
id int auto_increment
primary key,
name varchar(255) not null
);
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
public class TestSpringJDBCTemplate {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
JdbcTemplate jdbcTemplate = context.getBean("jdbcTemplate", JdbcTemplate.class);
System.out.println("test");
String sql = "insert into dept(name) values(?)";
// jdbcTemplate自动提交事务
jdbcTemplate.update(sql,"人事部");
}
}
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
public class TestSpringJDBCTemplate {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
JdbcTemplate jdbcTemplate = context.getBean("jdbcTemplate", JdbcTemplate.class);
String sql = "update dept set name=? where id=?";
// jdbcTemplate自动提交事务
jdbcTemplate.update(sql,"运维部",3);
}
}
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
public class TestSpringJDBCTemplate {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
JdbcTemplate jdbcTemplate = context.getBean("jdbcTemplate", JdbcTemplate.class);
String sql = "delete from dept where id = ?";
jdbcTemplate.update(sql,2);
}
}
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class TestSpringJDBCTemplate {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
JdbcTemplate jdbcTemplate = context.getBean("jdbcTemplate", JdbcTemplate.class);
List<Object[]> deptList = new ArrayList<>();
deptList.add(new Object[]{"测试部"});
deptList.add(new Object[]{"运维部"});
deptList.add(new Object[]{"测试部"});
String sql = "insert into dept(name) values(?)";
jdbcTemplate.batchUpdate(sql,deptList);
}
}
查询单个数值
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class TestSpringJDBCTemplate {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
JdbcTemplate jdbcTemplate = context.getBean("jdbcTemplate", JdbcTemplate.class);
String sql = "select count(1) from dept";
Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
System.out.printf("员工数量: %d%n", count);
}
}
查询单个对象
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import com.acaiblog.jdbc.pojo.Dept;
import org.springframework.jdbc.core.RowMapper;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class TestSpringJDBCTemplate {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
JdbcTemplate jdbcTemplate = context.getBean("jdbcTemplate", JdbcTemplate.class);
String sql = "select name from dept where id = ?";
RowMapper<Dept> rowMapper = new BeanPropertyRowMapper<>(Dept.class);
Dept dept = jdbcTemplate.queryForObject(sql, rowMapper, 3);
System.out.printf("dept: %s", dept);
}
}
查询多个对象
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import com.acaiblog.jdbc.pojo.Dept;
import org.springframework.jdbc.core.RowMapper;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class TestSpringJDBCTemplate {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
JdbcTemplate jdbcTemplate = context.getBean("jdbcTemplate", JdbcTemplate.class);
String sql = "select name from dept";
RowMapper<Dept> rowMapper = new BeanPropertyRowMapper<>(Dept.class);
List<Dept> dept = jdbcTemplate.query(sql, rowMapper);
System.out.printf("dept: %s", dept);
}
}
创建数据库表
create table book(
isbn varchar(50) primary key,
book_name varchar(100),
price int
);
create table book_stock(
isbn varchar(50) primary key,
stock int
);
create table account(
id int primary key,
username varchar(50),
balance int
);
pom.xml中添加依赖包
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.3.10version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-ormartifactId>
<version>5.3.10version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>5.3.10version>
dependency>
<dependency>
<groupId>org.mariadb.jdbcgroupId>
<artifactId>mariadb-java-clientartifactId>
<version>3.1.4version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.2.19version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13.2version>
<scope>testscope>
dependency>
dependencies>
resources下创建db.properties配置文件
db.driver=org.mariadb.jdbc.Driver
db.url= jdbc:mariadb://localhost:3306/jdbc
db.username=root
db.password=123456
resources下创建spring配置文件
<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: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/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="com.acaiblog.spring"/>
<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
bean>
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
<tx:annotation-driven>tx:annotation-driven>
beans>
创建图书接口
package com.acaiblog.spring.dao;
public interface BookShopDao {
// 根据图书编号查询图书价格
public Integer findBookPriceByIsbn(String isbn);
// 根据图书编号修改图书库存
public void updateBookStock(String isbn);
// 根据图书价格修改用户余额
public void updateUserAccount(String username, Integer price);
}
创建图书接口扩展
package com.acaiblog.spring.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository("bookShopDao")
public class BookShopDaoImpl implements BookShopDao{
@Autowired
@Qualifier("jdbcTemplate")
private JdbcTemplate jdbcTemplate;
/**
* 根据图书编号查询图书价格
* @param isbn
* @return
*/
@Override
public Integer findBookPriceByIsbn(String isbn){
String sql = "select price from book where isbn = ?";
return jdbcTemplate.queryForObject(sql, Integer.class,isbn);
}
/**
* 根据图书编号修改图书库存,每次只能购买一本图书,如果图书库存小于0返回异常
* @param isbn
*/
@Override
public void updateBookStock(String isbn) {
// 修改库存
String sql = "update book_stock set stock=stock-1 where isbn = ?";
jdbcTemplate.update(sql);
// 验证库存
String sql2 = "select stock from book_stock where isbn = ?";
Integer newStock = jdbcTemplate.queryForObject(sql2, Integer.class,isbn);
if(newStock <=0){
throw new RuntimeException("库存不足");
}
}
/**
* 根据图书价格修改用户余额,如果余额不足抛出异常
* @param username
* @param price
*/
@Override
public void updateUserAccount(String username, Integer price) {
// 查询余额是否充足
String sql = "select balance from account where username = ?";
Integer balance = jdbcTemplate.queryForObject(sql, Integer.class, username);
if(balance < price){
throw new RuntimeException("账户余额小于图书价格");
}
// 修改用户余额
String sql1 = "update account set balance = balance-? where username = ?";
jdbcTemplate.update(sql1,price,username);
}
}
@Transacitional注解属性
传播行为 | 描述 |
---|---|
REQUIRED | 如果当前存在事务,则加入该事务;否则,新建一个事务。 |
SUPPORTS | 如果当前存在事务,则加入该事务;否则,以非事务方式执行。 |
MANDATORY | 要求当前存在事务,如果不存在则抛出异常。 |
REQUIRES_NEW | 无论当前是否存在事务,都会创建一个新的事务。 |
NOT_SUPPORTED | 以非事务方式执行方法,如果当前存在事务,则将其挂起。 |
NEVER | 以非事务方式执行方法,如果当前存在事务,则抛出异常。 |
NESTED | 如果当前存在事务,则在一个嵌套的事务中执行;如果没有事务,则按REQUIRED行为创建一个新事务。 |
隔离级别 | 描述 |
---|---|
DEFAULT (使用数据库默认) | 使用数据库的默认隔离级别(通常为数据库配置的默认级别)。 |
READ_UNCOMMITTED (读未提交) | 允许读取尚未被其他事务提交的数据,存在脏读和不可重复读的风险。 |
READ_COMMITTED (读已提交) | 只能读取已经被其他事务提交的数据,避免脏读,但仍可能存在不可重复读。 |
REPEATABLE_READ (可重复读) | 确保在事务执行期间,其他事务不能修改数据,避免脏读和不可重复读。 |
SERIALIZABLE (串行化) | 最高隔离级别,确保事务串行执行,避免脏读、不可重复读和幻读。 |
<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: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/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="com.acaiblog.spring"/>
<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
bean>
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
<tx:annotation-driven>tx:annotation-driven>
<tx:advice id="tx" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="find*" read-only="true"/>
tx:attributes>
tx:advice>
beans>