如何快速入门java spring

Java领域Spring Cloud入门指南:快速搭建微服务架构 随着互联网业务的不断发展,单体应用架构逐渐暴露出可扩展性差、维护困难等问题,微服务架构应运而生。Spring Cloud作为Java领域中用于构建微服务架构的优秀框架,提供了一系列的工具和组件,帮助开发者轻松实现微服务的开发、部署和管理。本文的目的是为Java开发者提供一个详细的Spring Cloud入门指南,让读者能够快速掌握Spring Cloud的基本概念和使用方法,搭建起一个简单的微服务架构。 阅读详情

好记忆不如烂笔头, 能记下点什么, 就记下点什么, 方便后期的巩固

Spring介绍

Spring 是一个开源框架,是一个分层的 JavaEE 一站式框架。

所谓一站式框架是指 Spring 有 JavaEE 开发的每一层解决方案。

  • WEB层:SpringMVC

  • Service层:Spring的Bean管理,声明式事务

  • DAO层:Spring的JDBC模板,ORM模板

优点:

  • IOC:方便解耦合

  • AOP:对程序进行扩展

  • 轻量级框架

  • 方便与其他框架整合

Spring使用

Spring开发包解压后的目录介绍:

  • docs: Spring 开发规范和API

  • libs: Spring jar 包和源代码

  • schema: Spring 配置文件的约束

 

DataAccess 用于数据访问,WEB 用于页面显示,核心容器也就是IOC部分。

 

控制反转(IOC)

控制反转(Inversion of Control)是指将对象的创建权反转(交给)Spring。

使用IOC就需要导入IOC相关的包,也就是上图中核心容器中的几个包:beans,context,core,expression四个包。

 

实现原理

传统方式创建对象:

UserDAO userDAO=new UserDAO();

进一步面向接口编程,可以多态:

UserDAO userDAO=new UserDAOImpl();

这种方式的缺点是接口和实现类高耦合,切换底层实现类时,需要修改源代码。程序设计应该满足OCP元祖,在尽量不修改程序源代码的基础上对程序进行扩展。此时,可以使用工厂模式:

class BeanFactory{

    public static UserDAO getUserDAO(){

        return new UserDAOImpl();

    }

}

此种方式虽然在接口和实现类之间没有耦合,但是接口和工厂之间存在耦合。

使用工厂+反射+配置文件的方式,实现解耦,这也是 Spring 框架 IOC 的底层实现。

//xml配置文件

//<bean id="userDAO" class="xxx.UserDAOImpl"></bean>

class BeanFactory{

    public static Object getBean(String id){

        //解析XML

        //反射

        Class clazz=Class.forName();

        return clazz.newInstance();

    }

}

IOC XML 开发

在 docs 文件中包含了 xsd-configuration.hmtl 文件。其中定义了 beans schema。

<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

    <bean id="userService" class="x.y.UserServiceImpl">

    </bean>

</beans>

调用类:

ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");

UserService userService=(UserService)applicationContext.getBean("userService");

userService.save();

IOC 和 DI

DI 指依赖注入,其前提是必须有 IOC 的环境,Spring 管理这个类的时候将类的依赖的属性注入进来。

例如,在UserServiceImpl.java中:

public class UserServiceImpl implements UserService{

private String name;

public void setName(String name){

this.name=name;

}

public void save(){

System.out.println("save "+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="userService" class="spring.demo1.UserServiceImpl">

    <!--配置依赖的属性-->

     <property name="name" value="tony"/>

    </bean>

</beans>

测试代码:

@Test

public void demo2(){

//创建Spring工厂

ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");

UserService userService=(UserService)applicationContext.getBean("userService");

userService.save();

}

运行结果:

save tony

可以看到,在配置文件中配置的属性,在 Spring 管理该类的时候将其依赖的属性成功进行了设置。如果不使用依赖注入,则无法使用接口,只能使用实现类来进行设置,因为接口中没有该属性。

Spring 的工厂类

  • BeanFactory: 老版本的工厂类,在调用getBean()方法时,才会生成类的实例。

  • ApplicationContext: 在加载配置文件的时候,就会将 Spring 管理的类都实例化。有两个实现类:

    1. ClassPathXmlApplicationContext: 加载类路径下的配置文件

    2. FileSystemXmlApplicationContext: 加载磁盘下的配置文件

bean标签配置

  • id: 唯一约束,不能出现特殊字符

  • name: 理论上可以重复,但是开发中最好不要。可以出现特殊字符

生命周期:

  • init-method: bean被初始化的时候执行的方法

  • destroy-method: bean被销毁的时候执行的方法

作用范围:

  • scope: bean的作用范围,有如下几种,常用的是前两种

    • singleton: 默认使用单例模式创建

    • prototype: 多例

    • request: 在web项目中,spring 创建类后,将其存入到 request 范围中

    • session: 在web项目中,spring 创建类后,将其存入到 session 范围中

    • globalsession: 在web项目中,必须用在 porlet 环境

属性注入设置

  1. 构造方法方式的属性注入: Car 类在构造方法中有两个属性,分别为 name 和 price。

<bean id="car" class="demo.Car">

    <constructor-arg name="name" value="bmw">

    <constructor-arg name="price" value="123">

</bean>

  1. set 方法属性注入: Employee 类在有两个 set 方法,分别设置普通类型的 name 和引用类型的 Car (使用 ref 指向引用类型的 id 或  name)。

<bean id="employee" class="demo.Employee">

    <property name="name" value="xiaoming">

    <property name="car" ref="car">

</bean>

  1. P名称空间的属性注入: 首先需要引入p名称空间:

<beans xmlns="http://www.springframework.org/schema/beans"

    //引入p名称空间

    xmlns:p="http://www.springframework.org/schema/p"

    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>

如果是普通属性:

<bean id="car" class="demo.Car" p:name="bmv" p:price="123">

</bean>

如果是引用类型:

<bean id="employee" class="demo.Employee" p:name="xiaoming" p:car-ref:"car">

</bean>

  1. SpEL(Spring Expression Language)属性注入(Spring 3.x以上版本)

<bean id="car" class="demo.Car">

    <property name="name" value="#{'xiaoming'}">

    <property name="car" ref="#{car}">

</bean>

  1. 集合类型属性注入:

<bean id="car" class="demo.Car">

    <property name="namelist">

        <list>

            <value>qirui</value>

            <value>baoma</value>

            <value>benchi</value>

        </list>

    </property>

</bean>

多模块开发配置

  1. 在加载配置文件的时候,加载多个配置文件

  2. 在一个配置文件中引入多个配置文件,通过实现

IOC 注解开发

示例

  1. 引入jar包: 除了要引入上述的四个包之外,还需要引入aop包。

  2. 创建 applicationContext.xml ,使用注解开发引入 context 约束(xsd-configuration.html)

<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 definitions here -->

</beans>

  1. 组件扫描: 使用IOC注解开发,需要配置组件扫描,也就是哪些包下的类使用IOC的注解。

<context:component-scan base-package="demo1">

  1. 在类上添加注解

  2. 使用注解设置属性的值

属性如果有set方法,将属性注入的注解添加到set方法

属性没有set方法,将注解添加到属性上。

@Component("UserDao")//相当于配置了一个<bean> 其id为UserDao,对应的类为该类

public class UserDAOImpl implements UserDAO {

@Override

public void save() {

// TODO Auto-generated method stub

System.out.println("save");

} 

}

注解详解

  1. @Component

组件注解,用于修饰一个类,将这个类交给 Spring 管理。

有三个衍生的注解,功能类似,也用来修饰类。

  • @Controller:修饰 web 层类

  • @Service:修饰 service 层类

  • @Repository:修饰 dao 层类

2.属性注入

  • 普通属性使用 @Value 来设置属性的值

  • 对象属性使用 @Autowired  ,这个注解是按照类型来进行属性注入的。如果希望按照 bean 的名称或id进行属性注入,需要用 @Autowired 和 @Qualifier 一起使用

  • 实际开发中,使用 @Resource(name=" ") 来进行按照对象的名称完成属性注入

3.其他注解

  • @PostConstruct 相当于 init-method,用于初始化函数的注解

  • @PreDestroy 相当于 destroy-method,用于销毁函数的注解

  • @Scope 作用范围的注解,常用的是默认单例,还有多例 @Scope("prototype")

IOC 的 XML 和注解开发比较

  • 适用场景:XML 适用于任何场景;注解只适合自己写的类,不是自己提供的类无法添加注解。

  • 可以使用 XML 管理 bean,使用注解来进行属性注入

AOP开发

AOP 是 Aspect Oriented Programming 的缩写,意为面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术,是OOP的延续。

AOP 能够对程序进行增强,在不修改源码的情况下,可以进行权限校验,日志记录,性能监控,事务控制等。

也就是说功能分为两大类,一类是核心业务功能,一类是辅助增强功能。两类功能彼此独立进行开发。比如登录功能是核心业务功能,日志功能是辅助增强功能,如果有需要,将日志和登录编制在一起。辅助功能就称为切面,这种能选择性的、低耦合的把切面和核心业务功能结合的编程思想称为切面编程。

底层实现

JDK 动态代理只能对实现了接口的类产生代理。Cglib 动态代理可以对没有实现接口的类产生代理对象,生成的是子类对象。

使用 JDK 动态代理:

public interface UserDao {

public void insert();

public void delete();

public void update();

public void query();

}

实现类:

public class UserDaoImpl implements UserDao { @Override public void insert() { System.out.println("insert"); } @Override public void delete() { System.out.println("delete"); } @Override public void update() { System.out.println("update"); } @Override public void query() { System.out.println("query"); } }

JDK 代理:

public class JDKProxy implements InvocationHandler{

private UserDao userDao;

public JDKProxy(UserDao userDao){

this.userDao=userDao;

}

public UserDao createProxy(){

UserDao userDaoProxy=(UserDao)Proxy.newProxyInstance(userDao.getClass().getClassLoader(),

userDao.getClass().getInterfaces(), this);

return userDaoProxy;

}

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

if("update".equals(method.getName())){

System.out.println("权限校验");

return method.invoke(userDao, args);

}

return method.invoke(userDao, args);

}

}

通过动态代理增强了 update 函数。 测试类:

public class Demo1 {

@Test

public void demo1(){

UserDao userDao=new UserDaoImpl();

UserDao proxy=new JDKProxy(userDao).createProxy();

proxy.insert();

proxy.delete();

proxy.update();

proxy.query();

}

}

运行结果为:

insert

delete

权限校验

update

query

CglibCglib 是第三方开源代码生成类库,可以动态添加类的属性和方法。

与上边JDK代理不同,Cglib的使用方式如下:

public class CglibProxy implements MethodInterceptor{

//传入增强的对象

private UserDao customerDao;

public CglibProxy(UserDao userDao){

this.userDao=userDao;

}

public UserDao createProxy(){

Enhancer enhancer=new Enhancer();

enhancer.setSuperclass(userDao.getClass());

enhancer.setCallback(this);

UserDao proxy=(UserDao)enhancer.create();

return proxy;

}

@Override

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

if("save".equals(method.getName())){

System.out.println("enhance function");

return methodProxy.invokeSuper(proxy, args);

}

return methodProxy.invokeSuper(proxy, args);

}

}

如果实现了接口的类,底层采用JDK代理。如果不是实现了接口的类,底层采用 Cglib代理。

IOC与传统方式的比较

  1. 获取对象方式:传统通过 new 关键字主动创建一个对象。IOC 方式中,将对象的生命周期交给 Spring 管理,直接从 Spring 获取对象。也就是控制反转————将控制权从自己手中交到了 Spring 手中。

Spring 的 AOP 开发(AspectJ 的 XML 方式)

AspectJ 是一个 AOP 的框架,Spring 引入 AspectJ,基于 AspectJ 进行 AOP 的开发。

相关术语

  • Joinpoint: 连接点,可以被拦截到的点。也就是可以被增强的方法都是连接点。

  • Pointcut: 切入点,真正被拦截到的点,也就是真正被增强的方法

  • Advice: 通知,方法层面的增强。对某个方法进行增强的方法,比如对 save 方法进行权限校验,权限校验的方法称为通知。

  • Introduction: 引介,类层面的增强。

  • Target: 目标,被增强的对象(类)。

  • Weaving: 织入,将 advice 应用到 target 的过程。

  • Proxy: 代理对象,被增强的对象。

  • Aspect: 切面,多个通知和多个切入点的组合。

使用方法

  1. 引入相关包

  2. 引入配置文件

<?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"> <!-- bean definitions here -->

</beans>

  1. 编写目标类并配置:

public class ProductDaoImpl implements ProductDao {

@Override

public void save() {

System.out.println("save");

}

@Override

public void update() {

System.out.println("update");

}

@Override

public void find() {

System.out.println("find");

}

@Override

public void delete() {

System.out.println("delete");

}

}

<bean id="productDao" class="demo1.ProductDaoImpl"></bean>

  1. 编写切面类,假设用于权限验证并配置

public class MyAspectXML {

public void checkPri(){

System.out.println("check auth");

}

}

<bean id="myAspect" class="demo1.MyAspectXML"></bean>

  1. 通过AOP配置完成对目标类的增强

<aop:config>

<aop:pointcut expression="execution(* demo1.ProductDaoImpl.save(..))" id="pointcut1"/>

<aop:aspect ref="myAspect">

<aop:before method="chechPri" pointcut-ref="pointcut1"/>

</aop:aspect> 

</aop:config>

 

通知类型

  1. 前置通知:在目标方法执行前操作,可以获得切入点信息

<aop:before method="chechPri" pointcut-ref="pointcut1"/>

public void checkPri(JoinPoint joinPoint){

System.out.println("check auth "+joinPoint);

}

  1. 后置通知:在目标方法执行后操作,可以获得方法返回值

<aop:after-returning method="writeLog" pointcut-ref="pointcut2" returning="result"/>

public void writeLog(Object result){

    System.out.println("writeLog "+result);

}

  1. 环绕通知:在目标方法执行前和后操作,可以阻止目标方法执

<aop:around method="around" pointcut-ref="pointcut3"/>

public Object around(ProceedingJoinPoint joinPoint) throws Throwable{

System.out.println("before");

Object result=joinPoint.proceed();

System.out.println("after");

return result;

}

  1. 异常抛出通知:程序出现异常时操作

<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="ex"/>

public void afterThrowing(Throwable ex){

System.out.println("exception "+ex.getMessage());

}

  1. 最终通知:相当于finally块,无论代码是否有异常,都会执行

<aop:after method="finallyFunc" pointcut-ref="pointcut4"/>

public void finallyFunc(){

System.out.println("finally");

}

  1. 引介通知:不常用

Spring 切入点表达式

基于 execution 函数完成

语法:[访问修饰符] 方法返回值 包名.类名.方法名(参数)

其中任意字段可以使用*代替表示任意值

Spring 的 AOP 基于 AspectJ 注解开发

开发步骤

  1. 引入jar包

  2. 设置配置文件:

<?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"

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.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context.xsd

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop.xsd

http://www.springframework.org/schema/tx 

http://www.springframework.org/schema/tx/spring-tx.xsd">

</beans>

  1. 编写配置目标类

<bean id="orderDao" class="demo1.OrderDao"></bean>

public class OrderDao {

public void save(){

System.out.println("save order");

}

public void update(){

System.out.println("update order");

}

public void delete(){

System.out.println("delete order");

}

public void find(){

System.out.println("find order");

}

}

  1. 开启aop注解自动代理

<aop:aspectj-autoproxy/>

  1. 编写切面类并配置

@Aspect

public class MyAspectAnno {

@Before(value="execution(* demo1.OrderDao.save(..))")

public void before(){

System.out.println("before");

}

}

<bean id="myAspect" class="demo1.MyAspectAnno">

注解通知类型

  • @Before: 前置通知

  • @AfterReturning: 后置通知

@AfterReturning(value="execution(* demo1.OrderDao.save(..))",returning="result")

public void after(Object result){

System.out.println("after "+result);

}

  • @Around:环绕通知

@Around(value="execution(* demo1.OrderDao.save(..))")

public Object around(ProceedingJoinPoint joinPoint) throws Throwable{

System.out.println("before");

Object obj=joinPoint.proceed();

System.out.println("after");

return obj;

}

  • @AfterThrowing: 抛出异常

@AfterThrowing(value="execution(* demo1.OrderDao.save(..))",throwing="e")

public void afterThrowing(Throwable e){

System.out.println("exception:"+e.getMessage();

}

  • @After: 最终通知

@After(value="execution(* demo1.OrderDao.save(..))")

public void after(){

System.out.println("finally");

}

  • @PointCut:切入点注解

@PointCut(value="execution(* demo1.OrderDao.save(..))")

private void pointcut1(){}

此时,在上述通知的注解中,value可以替换为该函数名,例如:

@After(value="MyAspect.pointcut1()")

public void after(){

System.out.println("finally");

}

这个注解的好处是,只需要维护切入点即可,不用在修改时修改每个注解。

Spring 的 JDBC 模板

Spring 对持久层也提供了解决方案,也就是 ORM 模块和 JDBC 的模板。针对 JDBC ,提供了 org.springframework.jdbc.core.JdbcTemplate 作为模板类。

使用 JDBC 模板

  1. 引入jar包,数据库驱动,Spring 的 jdbc 相关包。

  2. 基本使用:

public void demo1(){

    //创建连接池

DriverManagerDataSource dataSource=new DriverManagerDataSource();

dataSource.setDriverClassName("com.mysql.jdbc.Driver");

dataSource.setUrl("jdbc:mysql:///spring4");

dataSource.setUsername("root");

dataSource.setPassword("123456");

//创建JDBC模板 

JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource);

jdbcTemplate.update("insert into account values (null,?,?)", "xiaoming",1000d);

}

  1. 将连接池和模板交给 Spring 管理

  • 配置文件:

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource;">

<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>

<property name="url" value="jdbc:mysql:///spring4"></property>

<property name="username" value="root"></property>

<property name="password" value="123456"></property>

</bean>

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate;"> 

<property name="dataSource" ref="dataSource"></property>

</bean>

  • 测试文件:

     

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("classpath:applicationContext.xml")

public class JdbcDemo2 {

@Resource(name="jdbcTemplate")

private JdbcTemplate jdbcTemplate;

@Test

public void demo2(){

jdbcTemplate.update("insert into account values (null,?,?)", "xiaolan",1000d);

}

}

使用开源数据库连接池

  1. 使用 DBCP 的配置:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">

<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>

<property name="url" value="jdbc:mysql://192.168.66.128/spring4"></property>

<property name="username" value="root"></property>

<property name="password" value="123456"></property>

  1. 使用 C3P0 的配置:

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">

<property name="driverClass" value="com.mysql.jdbc.Driver"></property>

<property name="jdbcUrl" value="jdbc:mysql://192.168.66.128/spring4"></property>

<property name="user" value="root"></property>

<property name="password" value="123456"></property>

</bean>

  1. 引入外部属性文件

首先建立外部属性文件:

jdbc.driverClass=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://192.168.66.128/spring4

jdbc.username=root

jdbc.password=123456

然后对属性文件进行配置:

<context:property-placeholder location="classpath:jdbc.properties"/>

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">

<property name="driverClass" value="${jdbc.driverClass}"></property>

<property name="jdbcUrl" value="${jdbc.url}"></property>

<property name="user" value="${jdbc.username}"></property>

<property name="password" value="${jdbc.password}"></property>

</bean>

CRUD操作

insert, update, delete 语句都借助模板的 update 方法进行操作。

public void demo(){

jdbcTemplate.update("insert into account values (null,?,?)", "xiaoda",1000d);

jdbcTemplate.update("update account set name=?,money=? where id=?", "xiaoda",1000d,2);

jdbcTemplate.update("delete from account where id=?", 6);

}

查询操作:

public void demo3(){

String name=jdbcTemplate.queryForObject("select name from account where id=?",String.class,5);

long count=jdbcTemplate.queryForObject("select count(*) from account",Long.class);

}

将返回的结果封装成为类:

public void demo4(){

Account account=jdbcTemplate.queryForObject("select * from account where id=?", new MyRowMapper(),5);

}

其中:

class MyRowMapper implements RowMapper<Account>{

@Override

public Account mapRow(ResultSet rs, int rowNum) throws SQLException {

Account account=new Account();

account.setId(rs.getInt("id"));

account.setName(rs.getString("name"));

account.setMoney(rs.getDouble("money"));

return account;

}

}

Spring的事务管理

事务

事务是指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败。

具有四个特性:

  • 原子性:事务不可分

  • 一致性:事务执行前后数据完整性保持一致

  • 隔离性:一个事务的执行不应该受到其他事务干扰

  • 持久性:一旦事务结束,数据就持久化到数据库

如果不考虑隔离性会引发安全性问题:

  • 读问题:

    • 脏读:一个事务读到另一个事务未提交的数据

    • 不可重复读:一个事务读到另一个事务已经提交的 update 数据,导致一个事务中多次查询结果不一致

    • 幻读:一个事务读到另一个事务已经提交的 insert 数据,导致一个事务中多次查询结果不一致

  • 写问题:

    • 丢失更新

解决读问题:设置事务隔离级别

  • Read uncommitted: 未提交读,无法解决任何读问题

  • Read committed: 已提交读,解决脏读问题

  • Repeatable read: 重复读,解决脏读和不可重复读问题

  • Serializable:序列化,解决所有读问题

事务管理API

  1. PlatformTransactionManager: 平台事务管理器

这是一个接口,拥有多个不同的实现类,如 DataSourceTransactionManager 底层使用了JDBC 管理事务; HibernateTransactionManager 底层使用了 Hibernate 管理事务。

  1. TransactionDefinition: 事务定义信息

用于定义事务的相关信息,如隔离级别、超时信息、传播行为、是否只读等

  1. TransactionStatus: 事务的状态

用于记录在事务管理过程中,事务的状态的对象。

上述API的关系: Spring 在进行事务管理的时候,首先平台事务管理器根据事务定义信息进行事务管理,在事务管理过程当中,产生各种此状态,将这些状态信息记录到事务状态的对象当中。

事务的传播行为

事务的传播行为主要解决业务层(Service)方法相互调用的问题,也就是不同的业务中存在不同的事务时,如何操作。

Spring 中提供了7种事务的传播行为,分为三类:

  • 保证多个操作在同一个事务中

    • PROPAGATION_REQUIRED: B方法调用A方法,如果A中有事务,使用A中的事务并将B中的操作包含到该事务中;否则新建一个事务,将A和B中的操作包含进来。(默认)

    • PROPAGATION_SUPPORTS:如果A中有事务,使用A的事务;否则不使用事务

    • PROPAGATION_MANDATORY:如果A中有事务,使用A的事务;否则抛出异常

  • 保证多个操作不在同一个事务中

    • PROPAGATION_REQUIRES_NEW:如果A中有事务,将其挂起,创建新事务,只包含自身操作。否则,新建一个事务,只包含自身操作。

    • PROPAGATION_NOT_SUPPORTED:如果A中有事务,挂起,不使用事务。

    • PROPAGATION_NEVER:如果A中有事务,抛出异常,也即不能用事务运行。

  • 嵌套事务

    • PROPAGATION_NESTED:如果A有事务,按照A的事务执行,执行完成后,设置一个保存点,然后执行B的操作。如果出现异常,可以回滚到最初状态或保存点状态。

实例

以转账为例,业务层的DAO层类如下:

public interface AccountDao {

public void outMoney(String from,Double money);

public void inMoney(String to,Double money);

}

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{

@Override

public void outMoney(String from, Double money) {

 this.getJdbcTemplate().update("update account set money = money - ? where name = ?",money,from);

}

@Override

public void inMoney(String to, Double money) {

this.getJdbcTemplate().update("update account set money = money + ? where name = ?",money,to);

}

}

public interface AccountService {

public void transfer(String from,String to,Double money);

}

public class AccountServiceImpl implements AccountService {

private AccountDao accountDao;

public void setAccountDao(AccountDao accountDao) {

this.accountDao = accountDao;

}

@Override

public void transfer(String from, String to, Double money) {

accountDao.outMoney(from, money);

accountDao.inMoney(to, money);

}

}

在xml中进行类的配置:

<bean id="accountService" class="tx.demo.AccountServiceImpl">

<property name="accountDao" ref="accountDao"/>

</bean>

<bean id="accountDao" class="tx.demo.AccountDaoImpl">

<property name="dataSource" ref="dataSource"/>

</bean>

 

事务管理1: 编程式事务管理

  1. 配置平台事务管理器

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource" ref="dataSource"></property>

</bean>

  1. 配置事务管理模板类

<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">

<property name="transactionManager" ref="transactionManager"></property>

</bean>

  1. 在业务层注入事务管理模板

<bean id="accountService" class="tx.demo1.AccountServiceImpl">

<property name="accountDao" ref="accountDao"/>

<property name="transactionTemplate" ref="transactionTemplate"/>

</bean>

  1. 编码实现事务管理

//ServiceImpl类中:

private TransactionTemplate transactionTemplate;

@Override

public void transfer(String from, String to, Double money) {

transactionTemplate.execute(new TransactionCallbackWithoutResult() {

@Override

protected void doInTransactionWithoutResult(TransactionStatus arg0) {

accountDao.outMoney(from, money);

accountDao.inMoney(to, money);

}

});

}

声明式事务管理(配置实现,基于AOP思想)

  1. XML 方式的声明式事务管理

  • 配置事务管理器

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource" ref="dataSource"></property>

</bean>

  • 配置事务通知

<tx:advice id="txAdvice" transaction-manager="transactionManager">

<tx:attributes>

<tx:method name="transfer" propagation="REQUIRED"/>

</tx:attributes>

</tx:advice>

  • 配置aop事务

<aop:config>

<aop:pointcut expression="execution(* tx.demo2.AccountServiceImpl.*(..))" id="pointcut1"/>

<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>

</aop:config>

  1. 注解方式

  • 配置事务管理器,和上方一致

  • 开启事务管理的注解:

<tx:annotation-driven transaction-manager="transactionManager"/>

  • 在使用事务的类上添加一个注解@Transactional

Spring Boot在Java领域的快速入门指南 本指南的主要目的是帮助Java开发者快速掌握Spring Boot的基本概念、开发流程和应用技巧。我们将涵盖Spring Boot的核心功能,包括依赖管理、自动配置、嵌入式服务器等。通过本指南,读者将能够使用Spring Boot开发简单的Web应用程序,并了解如何在实际项目中应用Spring Boot。核心概念与联系:介绍Spring Boot的核心概念和架构。核心算法原理 & 具体操作步骤:讲解Spring Boot的核心算法原理,并给出具体的操作步骤。 阅读详情

相关推荐

msb-client-websocket-java:Java客户端库,用于连接到MSB(制造服务总线)的websocket接口

Java的MSB Websocket客户端库 相容性矩阵 客户端版本与MSB版本的兼容性: 1.5.x发行 1.0.x X 欢迎 如果您想贡献,请阅读 。 如果要使用示例项目来测试此客户端。 如果您想知道如何在自己的项目中使用此客户端,请阅读以下内容。 什么是VFK MSB TODO:链接到有关VFK MSB的常规文档 您可以使用此客户端将Java应用程序连接到VFK MSB。 先决条件 通过Maven导入到您的应用程序 < properties> ... <!-- Use the latest version whenever possible. --> < msb>1.0.1-RELEASE</ msb> ... </ properties

Spring快速入门超详细讲解

在Spring框架规范中,所有由spring管理的对象都称之为Bean对象。Spring提供了以下多个注解,这些注解可以直接标注在java类上,将它们定义成Spring Bean。注解说明@Component该注解用于描述Spring中的Bean,它是一个泛化的概念,仅仅标识容器中的一 个组件(Bean),并且可以作用在任何层次,例如Service层、Dao层等,使用时只需将该注解标注在相应的类上即可。

南 阳 的博客 5086

LPDDR5时序精调:深入解析Read Gate Training的两种模式

本文深入解析了LPDDR5内存中关键的Read Gate Training技术,详细对比了RDQS Toggle Mode(翻转模式)与Enhanced RDQS Mode(增强模式)的工作原理、时序参数及适用场景。文章阐述了在高速数据传输下精准校准时序的必要性,并提供了两种模式的实战选型指南与系统级调试思路,帮助工程师优化内存性能与稳定性。

weixin_29219189的博客 366

lsb算法 java,Java中的LSB / MSB处理

小编典典这样做:result[5] = (byte) (value & 0xFF); // Least significant "byte"result[6] = (byte) ((value & 0xFF00) >> 8); // Most significant "byte"我通常使用位掩码-也许不需要它们。第一行选择低八位,第二行选择高八位,...

weixin_34817716的博客 801

无网环境也能玩转DBeaver?手把手教你离线安装与ClickHouse连接(附实测jar包)

本文详细介绍了在无网环境下如何离线安装DBeaver并配置ClickHouse连接的完整指南。通过准备必备工具如DBeaver安装包、ClickHouse JDBC驱动及Maven本地仓库,确保在物理隔离环境中实现数据库管理。文章包含详细的安装步骤、驱动配置和性能优化建议,帮助开发者在严格网络限制下高效工作。

weixin_42635064的博客 375

CIC-IDS-2018数据集高效预处理实战:从数据清洗到特征整合

本文详细介绍了CIC-IDS-2018数据集的高效预处理方法,从数据清洗到特征整合的全流程实战。通过内存优化、异常值处理和特征工程等技巧,帮助网络安全研究人员快速处理大规模网络流量数据,提升机器学习模型的训练效率和准确率。特别针对特征数据的预处理提供了实用代码示例和优化建议。

weixin_29274969的博客 502

快速入门Spring

Spring 实现类与类之间的解耦合:便于类与类之间的管理 1.轻量:运行时占用资源少,运行效率高,不依赖其他jar 2.解耦合:spring提供了ioc控制反转 实现了由容器管理对象,对象的依赖关系,原来在程序代码中实现对象的创建,现在由容器完成,实现对象之间的解耦合 3.aop的支持 4.可以集成各种优秀的框架(mybatis) 核心 ioc ​ DI(作为ioc的技术实现):依赖注入 只需要对象的名字,就可以使用对象 ​ spring底层使用的反射来创建对象 AOP 如果说 IoC 是 Sprin

ShiningBlueOcean 662

Flutter模块打包AAR集成Android原生项目实践

跨平台开发框架Flutter通过将UI组件渲染为原生代码实现高性能表现,其核心优势在于一套代码可同时运行在iOS和Android平台。在工程实践中,将Flutter模块打包为AAR(Android Archive)进行集成,成为混合开发的主流方案。这种方案既保留了原生项目的稳定性,又能渐进式引入Flutter的高效开发特性。通过配置MethodChannel实现原生与Dart代码通信,开发者可以灵活控制Flutter引擎生命周期,优化内存占用和渲染性能。对于电商、社交等需要快速迭代的业务场景,该方案能显著提

weixin_34025051的博客 398

Spring-第一篇-快速入门

本篇文章将会带领大家学习到一些关于spring快速入门的技巧,通过学习,可以达到了解spring到底是干嘛的,如何进行spring程序的编写。

weixin_44351616的博客 2632

200SMART PLC时间不准?手把手教你用MCGS触摸屏实现自动校时(附完整代码)

本文针对西门子200SMART PLC时钟不准的常见问题,提供了一套基于MCGS触摸屏的自动校时解决方案。文章详细阐述了时钟偏差的根源、时间同步方案的技术选型,并手把手指导如何配置MCGS与PLC的通信,以及编写完整的PLC时间读取、转换与设置代码,最终实现稳定可靠的自动时间同步功能。

jupyter5notebook的博客 452

【unity】解决unity编译器安装中文汉化包失败

查看是否有Localization目录如果没有就进行创建,然后点击打开Localization把下载的zh-hans.po文件复制剪切进去即可。如果有的同学中文包安装失败,我们找到相应的编译器版本,点击在资源管理器中显示按钮,我们找到简体中文,复制downloadUrl后面的值到浏览器打开进行下载,点击Edtior language选择框,选择简体中文,等待加载。我们点击当前目录的上一级,进入编译器目录。返回在文件管理器中点击Editor目录。编译器启动后点击Edit[编辑]按钮。复制或者剪切下载的文件。

weixin_44959182的博客 8022

GraphQL Java Spring 教程:快速入门与配置指南

GraphQL Java Spring 教程:快速入门与配置指南 1. 项目目录结构及介绍 此教程基于 graphql-java-spring 示例项目,其目录结构展示了如何在Spring应用中集成GraphQL。尽管直接链接指向的是GitHub仓库的基础库,我们假设一个典型的基于该技术栈的应用结构如下: ├── src │ ├── main │ │ ├── java │ │ ...

gitblog_00409的博客 937

手把手教你解决Windows 10网络驱动器无法访问问题(附详细排查步骤)

本文详细指导Windows 10用户解决网络驱动器无法访问的常见问题。通过从现象快速定位到系统排查,提供了从检查网络连通性、修复凭据权限到调整高级设置的完整步骤,特别是针对“找不到网络路径”等错误,帮助用户高效恢复对共享资源的访问。

weixin_29233857的博客 517

Java Spring快速入门

Spring是一个开源的企业级Java应用框架,其目标是简化企业级应用程序的开发。Spring框架的主要特点是依赖注入(Dependency Injection,简称DI)和面向切面编程(Aspect Oriented Programming,简称AOP)。Spring框架可以用于任何基于Java的应用,并且可以与许多其他框架无缝集成。IoC容器是一个应用程序上下文,它负责实例化、配置和管理对象。在Spring框架中,IoC容器负责将对象之间的依赖关系解析并注入到相应的对象中。

raw_inputhello的博客 1098

C# WinForm上位机:从串口调试工具到智能温控系统(Modbus RTU协议实战+完整源码)

做工业上位机开发时,我们常从串口调试工具入手:验证设备通信、查看数据帧,但面对实际场景(比如温控、电机控制),单纯的“收发数据”远远不够——需要解析工业标准协议(如Modbus RTU)、实时监控关键指标、实现自动化控制逻辑,还要有稳定的UI交互和数据记录。串口调试工具能收发数据,但看不懂Modbus RTU帧(地址、功能码、寄存器、CRC校验);想控制温控设备(如加热器、风扇),但不知道如何通过Modbus写入控制指令;手动调节目标温度时,温度波动大,需要PID算法实现精准控温,但不会集成;

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1301

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

视频教程-Spring框架快速入门到精通-Java

Spring框架快速入门到精通 十年项目开发经验,主要从事java相关的开发...

weixin_32656541的博客 177

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Spring Boot 入门:快速构建现代 Java 应用的利器

Spring Boot入门指南:快速构建Java应用 本文介绍了使用Spring Boot框架快速构建现代Java应用的入门方法。主要内容包括: 环境准备:需要JDK 17+、Maven、IDE和MySQL数据库 项目创建:推荐使用Spring Initializr生成项目结构 关键配置: 通过pom.xml添加Spring Boot Web、JPA和MySQL依赖 使用application.properties配置数据库连接 开发步骤: 创建实体类User并添加JPA注解 配置数据库连接和Hiberna

2302_80853925的博客 1177

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

java快速入门实例教程_Spring初学快速入门

本篇文章帮大家学习Spring初学快速入门,包含了Spring初学快速入门使用方法、操作技巧、实例演示和注意事项,有一定的学习价值,大家可以用来参考。1- 介绍本教程文章是基于以下编写的:Spring Framework 4.0.4 RELEASEEclipse 4.5 MARS (ok for Eclipse 4.4 LUNA)在本文中使用Maven来声明Spring库,而不是下载Spring库...

weixin_39953102的博客 117

快速入门Java+Spring Ai+deepseek 开发

通过这么一个短篇小文章 就已经接触到了 基于llm开发ai应用的门槛 我们在这次学习中 学习到了一些关于模型的知识 以及Spring ai的使用 ,这里我们复习一下逻辑llm是基于推理模型来完成对话的Spring ai的使用分为 配置client 如果需要上下文对话这需要开启advisors,并且添加到client配置项如果需要记录历史 则需要配置chatMemory并且添加新的到client的中之后就可以通过chatMemory来对会话的历史进行操作小拓展。

doomwatcher的博客 1580

java spring入门_Java Spring快速入门

一、Spring是什么?Spring是一个开源框架,Spring为简化企业级应用开发而生,使用Spring可以使简单的JavaBean实现以前只有EJB才能实现的功能。Spring是一个IOC(DI)和AOP容器框架。二、具体描述Spring轻量级:Spring是非侵入式的-基于Spring开发的应用中的对象可以不依赖Spring的API依赖注入:(DI-Dependency injection、...

weixin_29098117的博客 204

Spring Boot 入门指南:快速构建 Java 应用程序

本文将带你深入了解 Spring Boot,介绍其核心概念、主要特性和基本用法。通过详细的步骤和实例演示,帮助初学者快速上手,掌握如何使用 Spring Boot 构建一个简单的 Java Web 应用程序,并探索其强大的生态系统。

TVT 1162

Java | Spring框架 | 快速入门实战

Java | Spring框架 | 快速入门实战 并与大家分享AI+编程的实践玩法

yingzix688的博客 1047

【spring ai】java 实现RAG检索增强,超快速入门

spring ai rag 人工智能检索增强能力提升,快速入门

whisperzzza的博客 4148

Java Spring Data JPA快速入门:简化数据访问层开发

Spring Data JPA是Spring提供的一个用于简化JPA数据访问的框架。它利用Spring的强大功能,结合JPA规范,使得开发者可以通过定义简单的接口来完成数据库的CRUD(创建、读取、更新、删除)操作。Spring Data JPA会根据接口方法的命名规则自动生成对应的SQL语句,无需开发者手动编写复杂的SQL代码。此外,它还支持自定义查询方法,允许开发者使用@Query注解来编写自定义的SQL语句。

程序媛学姐的博客 1016

Spring Boot MVC Java Web App快速入门指南

Spring Boot MVC Java Web App快速入门指南 本指南将引导您了解在GitHub上的开源项目 springboot-mvc-java-web-app,该项目基于Spring Boot框架,用于构建模型视图控制器(Model-View-Controller, MVC)架构的Java Web应用。我们将深入探讨其核心结构、关键文件以及如何启动应用。 1. 目录结构及介绍 Spri...

gitblog_00008的博客 568
上一篇: 短时间如何过Java校招
下一篇: 终于明白阿里百度,总是拿ThreadLocal经常考验求职者了
msbjyJava
博客等级 码龄6年 5粉丝 25原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值