Spring事务管理

笑忘书丶 2021-01-23 01:25:18
spring 管理 事务 事务管理


Spring的事务管理

Spring的事务管理简化了传统的事务管理流程,提高了开发效率。但是首先先要了解Spring的数据库编程。

Spring的数据库编程

数据库编程是互联网编程的基础,Spring框架为开发者提供了JDBC模板模式,即jdbcTemplate,它可以简化许多代码,但在实际应用中jdbcTemplate使用并不常见,在大多数时候都采用Spring结合MyBatis进行开发。在这里,只讲述Spring的jdbcTemplate开发。

SpringJDBC的配置

本节Spring数据库编程主要使用的是SpringJDBC模块的core和DataSource包,core是JDBC的核心包,包括常用的JdbcTemplate类,DataSource是访问数据源的工具类包。如果要使用SpringJDBC操作数据库,需要进行配置,配置如下:

<!--配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!--Mysql驱动-->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<!--连接的url-->
<property name="url" value="jdbc:mysql://localhost:3306/spring?characterEncoding=utf-8"/>
<!--用户名密码的配置-->
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!--配置JDBC模板-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>

在上述示例中,配置JDBC模板需要将dataSource注入到jdbcTemplate,而在数据访问层(Dao)中需要使用jdbcTemplate时也需要将jdbcTemplate注入到对应的bean中。

@Repository("testDao")
public class TestDaoImpl implements TestDao {
@Autowired //按照类型注入
private JdbcTemplate jdbcTemplate;

JDBCTemplate的常用方法

public int update(String sql,Object args[]):该方法可以对数据表进行增加、修改、删除。使用args[]设置参数,函数返回的是更新的行数。示例如下:

String insertSQL="insert into user values(NULL,?,?)";
Onject param[] = {"chencheng","m"};
jdbcTemplate.update(insertSQL,param);

public List<T> query(String sql,RowMapper<T> rowmapper,Object args[]):该方法可以对数据表进行查询操作,rowMapper将结果集映射到用户自定义的类中(前提是类的属性名与字段名相同)。示例如下:

jdbcTemplate.query(sql,new BeanPropertyRowMapper<User>(User.class),param);

具体的实现步骤

  1. 创建并编辑配置文件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"
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">
<!--指定需要扫描的包-->
<context:component-scan base-package="com.ch5"/>
<!--配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!--Mysql驱动-->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<!--连接的url-->
<property name="url" value="jdbc:mysql://localhost:3306/spring?characterEncoding=utf-8"/>
<!--用户名密码的配置-->
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!--配置JDBC模板-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
  1. 创建映射数据库的实体类
package com.ch5;
public class User {
private Integer id;
private String name;
private double money;
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 double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
  1. 创建数据库访问层TestDao和TestDaoImpl
package com.ch5.dao;
import com.ch5.User;
import java.util.List;
public interface TestDao {
public int update(String sql,Object[] param);
public List<User> query(String sql,Object[] param);
}
package com.ch5.dao.Impl;
import com.ch5.User;
import com.ch5.dao.TestDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository("testDao")
public class TestDaoImpl implements TestDao {
@Autowired //按照类型注入
private JdbcTemplate jdbcTemplate;
@Override
public int update(String sql, Object[] param) {
return jdbcTemplate.update(sql,param);
}
@Override
public List<User> query(String sql, Object[] param) {
return jdbcTemplate.query(sql,new BeanPropertyRowMapper<User>(User.class),param);
}
}
  1. 编写测试类JdbcTemplateTest
package com.ch5.Test;
import com.ch5.User;
import com.ch5.dao.TestDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
public class JdbcTemplateTest {
public static void main(String[] args) {
ApplicationContext appCo = new ClassPathXmlApplicationContext("appliationContext.xml");
TestDao testDao=(TestDao)appCo.getBean("testDao");
String insertSql="insert into account values(null,?,?)";
Object param[] = {"chencheng",1050.0};
testDao.update(insertSql,param);
String selectSql="select * from account";
List<User> list=testDao.query(selectSql,null);
for (User user : list) {
System.out.println(user);
}
}
}

编程式事务管理

在代码中显式的调用beginTransactioncommitrollback等与事务处理相关的方法,这就是编程式事务管理,当只有少数事务操作时,编程式事务管理才比较适合。

基于XML的AOP实现事务控制

  1. 编写事务管理的类
package com.itheima.utils;
/**
* 和事务管理相关的工具类,它包含了,开启事务,提交事务,回滚事务和释放连接
*/
public class TransactionManager {
private ConnectionUtils connectionUtils;
public void setConnectionUtils(ConnectionUtils connectionUtils) {
this.connectionUtils = connectionUtils;
}
/**
* 开启事务
*/
public void beginTransaction(){
try {
connectionUtils.getThreadConnection().setAutoCommit(false);
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 提交事务
*/
public void commit(){
try {
connectionUtils.getThreadConnection().commit();
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 回滚事务
*/
public void rollback(){
try {
connectionUtils.getThreadConnection().rollback();
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 释放连接
*/
public void release(){
try {
connectionUtils.getThreadConnection().close();//还回连接池中
connectionUtils.removeConnection();
}catch (Exception e){
e.printStackTrace();
}
}
}
  1. 配置aop
<!-- 配置事务管理器-->
<bean id="txManager" class="com.itheima.utils.TransactionManager">
<!-- 注入ConnectionUtils -->
<property name="connectionUtils" ref="connectionUtils"></property>
</bean>
<aop:config>
<aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.*.*(..)"/>
<aop:aspect id="txAdvice" ref="txManager">
<!--配置前置事务,开启事务-->
<aop:before method="beginTransaction" pointcut-ref="pt1"/>
<!--配置后置事务,提交事务-->
<aop:after-returning method="commit" pointcut-ref="pt1"/>
<!--配置异常事务,回滚事务-->
<aop:after-throwing method="rollback" pointcut-ref="pt1"/>
<!--配置最终事务,释放连接-->
<aop:after method="release" pointcut-ref="pt1"/>
</aop:aspect>
</aop:config>

基于底层API的编程式事务管理

基于底层API的编程式事务管理就是根据PlatformTransactionManagerTransactionDefinitionTeansactionStatus等几个核心接口,通过编程的方式进行事务管理,下面通过一个实例描述底层API的事务管理实现:

  1. 给数据源配置事务管理器
<!--配置事务管理器-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
  1. 创建数据访问类
package com.ch5.dao.Impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
@Repository("codeTransaction")
public class CodeTransaction {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private DataSourceTransactionManager transactionManager;
public String testTransaction(){
//默认事务定义
TransactionDefinition definition=new DefaultTransactionDefinition();
//开启事务
TransactionStatus transactionStatus = transactionManager.getTransaction(definition);
String message="执行成功,没有回滚";
try{
String sql = "delete * from account";
String insertSql = "insert into account values(?,?,?)";
Object param[] = {"1","chenheng",2000};
jdbcTemplate.update(sql);
//id重复,因此发生错误。
jdbcTemplate.update(insertSql,param);
jdbcTemplate.update(insertSql,param);
//提交事务
transactionManager.commit(transactionStatus);
}catch (Exception e){
//出现异常,回滚
transactionManager.rollback(transactionStatus);
message="事务回滚";
e.printStackTrace();
}
return message;
}
}
  1. 定义测试类
package com.ch5.Test;
import com.ch5.dao.Impl.CodeTransaction;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TransactionMangagerTest {
public static void main(String[] args) {
ApplicationContext appCo=new ClassPathXmlApplicationContext("appliationContext.xml");
CodeTransaction codeTransaction = (CodeTransaction)appCo.getBean("codeTransaction");
String result = codeTransaction.testTransaction();
System.out.println(result);
}
}

基于TransactionTemplate的编程式事务管理

事务处理的代码散落在业务逻辑代码中,破坏了原有代码的条理性,并且每一个事务都会有类似的启动事务,提交以及回滚事务的代码。

TransactionTemplateexcute方法有一个TransactionCallback接口类型的参数,该接口定义了一个DoInTransaction的方法,通常以匿名内部类的方式实现TransactionCallback接口,并在其doInTransaction方法中写业务逻辑代码。在这里可以使用默认的事务提交和回滚规则,在业务代码中不需要显式调用任何事务处理的API,doInTransaction方法有一个TransactionStatus类型的参数,可以在方法的任何位置调用该参数的setRollbackOnly方法将事务标识为回滚,以执行事务回滚。

根据默认规则,如果在执行回调方法的过程中抛出未检查异常,或者显式调用了setRollbackOnly方法,则回滚事务;如果事务执行完成或者抛出了checked类型的异常,则提交事务。

基于TransactionTemplate的编程式事务管理的步骤如下:

  1. 为事务管理添加事务模板:在基于底层的API开发的applicationContext.xml配置文件上使用springframwork提供的org,springframework,transaction.support.TransactionTemplate类为事务管理器添加事务模板。完整的配置文件如下:
<?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">
<!--指定需要扫描的包-->
<context:component-scan base-package="com.ch5"/>
<!--配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!--Mysql驱动-->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<!--连接的url-->
<property name="url" value="jdbc:mysql://localhost:3306/spring?characterEncoding=utf-8"/>
<!--用户名密码的配置-->
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!--配置事务管理器-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--为事务管理器txManager创建transactionTemplate-->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="txManager"/>
</bean>
<!--配置JDBC模板-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
  1. 创建数据访问类TransactionTemplateDao
package com.ch5;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
@Repository("transactionTemplateDao")
public class TransactionTemplateDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private TransactionTemplate transactionTemplate;
String message = "";
public String TransactionTemplateTest(){
//以你命好内部类的方式实现TransactionCallback接口。使用默认的事务规则。
transactionTemplate.execute(new TransactionCallback<Object>() {
@Override
public Object doInTransaction(TransactionStatus status) {
String insertSql = "insert into account values(?,?,?)";
Object param[] = {9,"chen",5000.0};
try{
jdbcTemplate.update(insertSql,param);
jdbcTemplate.update(insertSql,param);
message="执行成功,未回滚";
}catch (Exception e){
message="事务回滚";
}
return message;
}
});
return message;
}
}
  1. 创建测试类TransactionTemplateDaoTest
package com.ch5.Test;
import com.ch5.TransactionTemplateDao;
import com.ch5.dao.Impl.CodeTransaction;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TransactionTemplateDaoTest {
public static void main(String[] args) {
ApplicationContext appCo=new ClassPathXmlApplicationContext("appliationContext.xml");
TransactionTemplateDao transactionTemplateDao = appCo.getBean("transactionTemplateDao", TransactionTemplateDao.class);
String result = transactionTemplateDao.TransactionTemplateTest();
System.out.println(result);
}
}

声明式事务管理

Spring的声明式事务管理是通过AOP技术实现的事务管理,其本质是对方法前后拦截,然后再目标方法开始之前创建一个事务,在执行完成后提交或回滚事务。

与编程式事务管理相比较,声明式事务唯一不足的地方是最细粒度只能作用到方法级别,无法做到像编程式事务管理那样可以作用到代码块级别,但即便有这样的需要,可以通过变通方法进行解决。例如可以将要进行事务处理的代码块单独封装为方法。

Spring声明式事务管理可以通过两种方式实现,一是基于XML方式,二是基于@Transactional注解的方式

基于XML方式的声明式事务管理

基于XML方式的声明式事务管理是通过在配置文件中配置事务规则的相关声明来实现的。Spring提供了tx命名空间来配置事务管理,提供了<tx:advice>元素来配置事务的通知,在配置<tx:advice>时一般要指定id和transaction-manager属性,其中id是配置文件的唯一标识。transaction-manager指定了事务管理器。另外还需要配置<tx:attributes>子元素,该子元素可配置多个<tx:method>子元素决定执行事务的细节。

<tx:advice>元素配置了事务的增强处理后就可以通过编写AOP配置让Spring自动对目标对象生成代理,下面通过实例演示XML方式让Spring实现声明式事务管理。为了体现事务管理的流程,创建Dao、Service、Controller3层实现。

  1. 创建Dao接口和实现类
package statment.dao;
public interface TestDao {
public int save(String sql,Object param[]);
public int delete(String sql,Object param[]);
}
package statment.dao.Impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import statment.dao.TestDao;
@Repository("testDao")
public class TestDaoImpl implements TestDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public int save(String sql, Object[] param) {
return jdbcTemplate.update(sql,param);
}
public int delete(String sql, Object[] param) {
return jdbcTemplate.update(sql,param);
}
}
  1. 创建Service接口和实现类
package statment.Service;
public interface TestService {
public void test();
}
package statment.Service.Impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import statment.Service.TestService;
import statment.dao.TestDao;
@Service("testService")
public class TestServiceImpl implements TestService {
@Autowired
private TestDao testDao;
public void test() {
String deleteSql="delete from account";
String saveSql="insert into account values(?,?,?)";
Object param[] = {1,"shitji",5000};
testDao.delete(deleteSql,null);
testDao.save(saveSql,param);
}
}
  1. 创建Controller类
package statment.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import statment.Service.TestService;
@Controller
public class StatementController {
@Autowired
private TestService testService;
public void test(){
testService.test();
}
}
  1. 编写配置文件bean.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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
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">
<context:component-scan base-package="statment"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/spring"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:advice id="myAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="txPonintCut" expression="execution(* statment.Service.*.*(..))"/>
<aop:advisor advice-ref="myAdvice" pointcut-ref="txPonintCut"/>
</aop:config>
</beans>
  1. 编写测试类
package statment.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import statment.controller.StatementController;
public class XMLTest {
public static void main(String[] args) {
ApplicationContext appCo=new ClassPathXmlApplicationContext("bean.xml");
StatementController controller = appCo.getBean("statementController", StatementController.class);
controller.test();
}
}

基于注解的声明式事务管理

package statment.Service.Impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import statment.Service.TestService;
import statment.dao.TestDao;
@Service("testService")
@Transactional
public class TestServiceImpl implements TestService {
@Autowired
private TestDao testDao;
public void test() {
String deleteSql="delete from account";
String saveSql="insert into account values(?,?,?)";
Object param[] = {1,"shitji",5000};
testDao.delete(deleteSql,null);
testDao.save(saveSql,param);
}
}

加入@Transactional,就可以指定这个类需要受到Spring的事务管理,注意该注解只针对public修饰的方法添加。

在事务处理中捕获异常

声明式事务处理的流程是:

  1. Spring根据配置完成事务定义,设置事务属性。
  2. 执行开发者的代码逻辑。
  3. 如果开发者的代码产生异常并且满足事务回滚的配置条件,则事务回滚,否则提交事务。
  4. 事务资源释放。

如果开发者在代码逻辑中加入try...catch语句,Spring不能在声明式事务处理中正常执行事务的回滚。原因是Spring只在发生未被捕获的RuntimeException时才会回滚事务。因此需要处理这种问题。

基于XML方式的声明式事务管理中捕获异常

在基于XML方式的声明式事务管理捕获异常,需要补充两个步骤:

  1. 修改声明事务的配置
<tx:method name="*" rollback-for="java.lang.Exception"/>
  1. 在catch语句中添加throw new RuntimeException();

基于注解方式的声明式事务管理中捕获异常

  1. 修改注解内容,添加rollbackFor属性
@Transactional(rollbackFor = {Exception.class})
  1. 在catch语句中添加throw new RuntimeException();
版权声明
本文为[笑忘书丶]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/acknowledge/p/14315547.html

  1. 【计算机网络 12(1),尚学堂马士兵Java视频教程
  2. 【程序猿历程,史上最全的Java面试题集锦在这里
  3. 【程序猿历程(1),Javaweb视频教程百度云
  4. Notes on MySQL 45 lectures (1-7)
  5. [computer network 12 (1), Shang Xuetang Ma soldier java video tutorial
  6. The most complete collection of Java interview questions in history is here
  7. [process of program ape (1), JavaWeb video tutorial, baidu cloud
  8. Notes on MySQL 45 lectures (1-7)
  9. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  10. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  11. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  12. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  13. 【递归,Java传智播客笔记
  14. [recursion, Java intelligence podcast notes
  15. [adhere to painting for 386 days] the beginning of spring of 24 solar terms
  16. K8S系列第八篇(Service、EndPoints以及高可用kubeadm部署)
  17. K8s Series Part 8 (service, endpoints and high availability kubeadm deployment)
  18. 【重识 HTML (3),350道Java面试真题分享
  19. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  20. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  21. [re recognize HTML (3) and share 350 real Java interview questions
  22. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  23. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  24. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  25. RPC 1: how to develop RPC framework from scratch
  26. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  27. RPC 1: how to develop RPC framework from scratch
  28. 一次性捋清楚吧,对乱糟糟的,Spring事务扩展机制
  29. 一文彻底弄懂如何选择抽象类还是接口,连续四年百度Java岗必问面试题
  30. Redis常用命令
  31. 一双拖鞋引发的血案,狂神说Java系列笔记
  32. 一、mysql基础安装
  33. 一位程序员的独白:尽管我一生坎坷,Java框架面试基础
  34. Clear it all at once. For the messy, spring transaction extension mechanism
  35. A thorough understanding of how to choose abstract classes or interfaces, baidu Java post must ask interview questions for four consecutive years
  36. Redis common commands
  37. A pair of slippers triggered the murder, crazy God said java series notes
  38. 1、 MySQL basic installation
  39. Monologue of a programmer: despite my ups and downs in my life, Java framework is the foundation of interview
  40. 【大厂面试】三面三问Spring循环依赖,请一定要把这篇看完(建议收藏)
  41. 一线互联网企业中,springboot入门项目
  42. 一篇文带你入门SSM框架Spring开发,帮你快速拿Offer
  43. 【面试资料】Java全集、微服务、大数据、数据结构与算法、机器学习知识最全总结,283页pdf
  44. 【leetcode刷题】24.数组中重复的数字——Java版
  45. 【leetcode刷题】23.对称二叉树——Java版
  46. 【leetcode刷题】22.二叉树的中序遍历——Java版
  47. 【leetcode刷题】21.三数之和——Java版
  48. 【leetcode刷题】20.最长回文子串——Java版
  49. 【leetcode刷题】19.回文链表——Java版
  50. 【leetcode刷题】18.反转链表——Java版
  51. 【leetcode刷题】17.相交链表——Java&python版
  52. 【leetcode刷题】16.环形链表——Java版
  53. 【leetcode刷题】15.汉明距离——Java版
  54. 【leetcode刷题】14.找到所有数组中消失的数字——Java版
  55. 【leetcode刷题】13.比特位计数——Java版
  56. oracle控制用户权限命令
  57. 三年Java开发,继阿里,鲁班二期Java架构师
  58. Oracle必须要启动的服务
  59. 万字长文!深入剖析HashMap,Java基础笔试题大全带答案
  60. 一问Kafka就心慌?我却凭着这份,图灵学院vip课程百度云