spring事务实现方式有哪些?


参考答案
  • 编程式事务管理,在代码中调用 commit()、rollback()等事务管理相关的方法

maven pom.xml文件

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>4.2.4.RELEASE</version>
</dependency>
 
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.2.4.RELEASE</version>
</dependency>
 
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>4.2.4.RELEASE</version>
</dependency>
 
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>4.2.4.RELEASE</version>
</dependency>
 
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>4.2.4.RELEASE</version>
</dependency>
 
<!-- mysql驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.18</version>
</dependency>

 

编程式事务管理,可以通过 java.sql.Connection 控制事务。spring 配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
        
    <bean id="driver" class="com.mysql.jdbc.Driver"></bean>
 
    <bean id="datasource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
        <constructor-arg index="0" name="driver" ref="driver" />
        <constructor-arg index="1">
            <value>jdbc:mysql://localhost:3306/test</value>
        </constructor-arg>
        <constructor-arg index="2">
            <value>root</value>
        </constructor-arg>
        <constructor-arg index="3">
            <value>root</value>
        </constructor-arg>
    </bean>
    
</beans>

 

测试代码

package constxiong.interview.transaction;
 
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
 
import javax.sql.DataSource;
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
public class TransactionTest {
 
    public static void main(String[] args) throws Exception {
        testManualTransaction();//测试函数式控制事务
    }
    
    private static void testManualTransaction() throws SQLException {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring_transaction.xml");
        DataSource ds = (DataSource)context.getBean("datasource");
        Connection conn = ds.getConnection();
        try {
            initTable(conn);//初始化表
            conn.setAutoCommit(false);//设置不自动提交事务
            queryUsers(conn);//查询打印用户表
            deleteUser(conn);//删除 id=1 用户
            conn.rollback();//回滚
            queryUsers(conn);//查询打印用户表
        } finally {
            conn.close();
        }
    }
 
    private static void initTable(Connection conn) throws SQLException {
        conn.createStatement().execute("drop table if exists user");
        conn.createStatement().execute("create table user(id int, username varchar(60)) ENGINE=InnoDB DEFAULT CHARSET=utf8 ");//是否支持事务与数据库引擎有关,此处删除 ENGINE=InnoDB DEFAULT CHARSET=utf8 可能不支持事务
        conn.createStatement().execute("insert into user values(1, 'user1')");
        conn.createStatement().execute("insert into user values(2, 'user2')");
    }
 
    private static void deleteUser(Connection conn) throws SQLException {
        conn.createStatement().execute("delete from user where id = 1");
    }
 
    private static void queryUsers(Connection conn) throws SQLException {
        Statement st = conn.createStatement();
        st.execute("select * from user");
        ResultSet rs = st.getResultSet();
        while (rs.next()) {
            System.out.print(rs.getString("id"));
            System.out.print(" ");
            System.out.print(rs.getString("username"));
            System.out.println();
        }
    }
    
}

 

删除用户语句回滚,打印出两个用户

1 user1
2 user2
1 user1
2 user2

 

  • 基于 TransactionProxyFactoryBean 的声明式事务管理

新增 UserDao 接口

package constxiong.interview.transaction;
 
import java.util.List;
import java.util.Map;
 
public interface UserDao {
 
    /**
     * 查询用户
     * @return
     */
    public List<Map<String, Object>> getUsers();
    
    /**
     * 删除用户
     * @param id
     * @return
     */
    public int deleteUser(int id);
    
}

 

新增 UserDao 实现

package constxiong.interview.transaction;
 
import java.util.List;
import java.util.Map;
 
import org.springframework.jdbc.core.support.JdbcDaoSupport;
 
public class UserDaoImpl extends JdbcDaoSupport implements UserDao {
    
    /**
     * 查询用户
     * @return
     */
    public List<Map<String, Object>> getUsers() {
        String sql = "select * from user";
        return this.getJdbcTemplate().queryForList(sql);
    }
    
    /**
     * 删除用户
     * @param id
     * @return
     */
    public int deleteUser(int id){
        String sql = "delete from user where id = " + id;
        int result = this.getJdbcTemplate().update(sql);
        if (id == 1) {
            throw new RuntimeException();
        }
        return result;
    }
}

 

修改 spring 配置文件,添加事务管理器 DataSourceTransactionManager 和事务代理类 TransactionProxyFactoryBean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
        
    <bean id="driver" class="com.mysql.jdbc.Driver"></bean>
    
    <bean id="datasource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
        <constructor-arg index="0" name="driver" ref="driver" />
        <constructor-arg index="1">
            <value>jdbc:mysql://localhost:3306/test</value>
        </constructor-arg>
        <constructor-arg index="2">
            <value>root</value>
        </constructor-arg>
        <constructor-arg index="3">
            <value>root</value>
        </constructor-arg>
    </bean>
    
    <bean id="userDao" class="constxiong.interview.transaction.UserDaoImpl">
        <property name="dataSource" ref="datasource"></property>
    </bean>
    
    <!-- 事务管理器 -->
    <bean id="tracnsactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"></property>
    </bean>
    
    <bean id="userProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager" ref="tracnsactionManager"></property>
        <property name="target" ref="userDao"></property>
        <property name="transactionAttributes">
            <props>
                <!-- 主要 key 是方法   
                    ISOLATION_DEFAULT  事务的隔离级别
                    PROPAGATION_REQUIRED  传播行为
                -->
                <!-- -Exception 表示发生指定异常回滚,+Exception 表示发生指定异常提交 -->
                <prop key="deleteUser">-java.lang.RuntimeException</prop>
            </props>
        </property>
    </bean>
    
</beans>

 

测试代码

package constxiong.interview.transaction;
 
import java.util.Map;
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
public class TransactionTest {
 
    static ApplicationContext context = new ClassPathXmlApplicationContext("spring_transaction.xml");
    
    public static void main(String[] args) throws Exception {
        testUseTransactionProxy(); //测试使用 spring TransactionProxyFactoryBean
    }
    
    private static void testUseTransactionProxy() {
        final UserDao userDao = (UserDao)context.getBean("userProxy");
        printUsers(userDao);//打印用户
        userDao.deleteUser(1);//删除 id=1 用户
    }
 
    private static void printUsers(UserDao userDao) {
        for (Map<String, Object> user : userDao.getUsers()) {
            System.out.println(user);
        }
    }
 
}

 

 结果输出

{id=1, username=user1}
{id=2, username=user2}
Exception in thread "main" java.lang.RuntimeException
    at constxiong.interview.transaction.UserDaoImpl.deleteUser(UserDaoImpl.java:28)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
    at com.sun.proxy.$Proxy3.deleteUser(Unknown Source)
    at constxiong.interview.transaction.TransactionTest.testUseTransactionProxy(TransactionTest.java:32)
    at constxiong.interview.transaction.TransactionTest.main(TransactionTest.java:13)

 

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

UserDaoImpl 删除用户方法添加注解 @Transactional(rollbackFor=RuntimeException.class) 出现 RuntimeException 回滚

package constxiong.interview.transaction;
 
import java.util.List;
import java.util.Map;
 
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.transaction.annotation.Transactional;
 
public class UserDaoImpl extends JdbcDaoSupport implements UserDao {
    
    /**
     * 查询用户
     * @return
     */
    public List<Map<String, Object>> getUsers() {
        String sql = "select * from user";
        return this.getJdbcTemplate().queryForList(sql);
    }
    
    /**
     * 删除用户
     * @param id
     * @return
     */
    @Transactional(rollbackFor=RuntimeException.class)
    public int deleteUser(int id){
        String sql = "delete from user where id = " + id;
        int result = this.getJdbcTemplate().update(sql);
        if (id == 1) {
            throw new RuntimeException();
        }
        return result;
    }
}

 

修改 spring 配置文件,开启 spring 的事务注解能力

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    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-3.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
        
    <bean id="driver" class="com.mysql.jdbc.Driver"></bean>
    
    <bean id="datasource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
        <constructor-arg index="0" name="driver" ref="driver" />
        <constructor-arg index="1">
            <value>jdbc:mysql://localhost:3306/test</value>
        </constructor-arg>
        <constructor-arg index="2">
            <value>root</value>
        </constructor-arg>
        <constructor-arg index="3">
            <value>root</value>
        </constructor-arg>
    </bean>
    
    <bean id="userDao" class="constxiong.interview.transaction.UserDaoImpl">
        <property name="dataSource" ref="datasource"></property>
    </bean>
    
    <!-- 事务管理器 -->
    <bean id="tracnsactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"></property>
    </bean>
    
    <!-- 启用事务注解 -->
    <tx:annotation-driven transaction-manager="tracnsactionManager"/>
    
</beans>

 

测试代码

package constxiong.interview.transaction;
 
import java.util.Map;
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
public class TransactionTest {
 
    static ApplicationContext context = new ClassPathXmlApplicationContext("spring_transaction.xml");
    
    public static void main(String[] args) throws Exception {
        testAnnotationTransaction();
    }
    
    
    private static void testAnnotationTransaction() {
        UserDao userDao = (UserDao)context.getBean("userDao");
        printUsers(userDao);
        userDao.deleteUser(1);
    }
 
 
    private static void printUsers(UserDao userDao) {
        for (Map<String, Object> user : userDao.getUsers()) {
            System.out.println(user);
        }
    }
 
}

 

输出结果

{id=1, username=user1}
{id=2, username=user2}
Exception in thread "main" java.lang.RuntimeException
    at constxiong.interview.transaction.UserDaoImpl.deleteUser(UserDaoImpl.java:30)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
    at com.sun.proxy.$Proxy5.deleteUser(Unknown Source)
    at constxiong.interview.transaction.TransactionTest.testAnnotationTransaction(TransactionTest.java:20)
    at constxiong.interview.transaction.TransactionTest.main(TransactionTest.java:13)

 

  • 基于 Aspectj AOP 配置(注解)事务

maven pom.xml 添加 Aspectj 的支持

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.13</version>
</dependency>

 

去除 UserDaoImpl 注解@Transactional(rollbackFor=RuntimeException.class)

package constxiong.interview.transaction;
 
import java.util.List;
import java.util.Map;
 
import org.springframework.jdbc.core.support.JdbcDaoSupport;
 
public class UserDaoImpl extends JdbcDaoSupport implements UserDao {
    
    /**
     * 查询用户
     * @return
     */
    public List<Map<String, Object>> getUsers() {
        String sql = "select * from user";
        return this.getJdbcTemplate().queryForList(sql);
    }
    
    /**
     * 删除用户
     * @param id
     * @return
     */
    public int deleteUser(int id){
        String sql = "delete from user where id = " + id;
        int result = this.getJdbcTemplate().update(sql);
        if (id == 1) {
            throw new RuntimeException();
        }
        return result;
    }
}

 

修改 spring 配置文件,织入切面

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    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/tx
        http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
        
    <bean id="driver" class="com.mysql.jdbc.Driver"></bean>
    
    <bean id="datasource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
        <constructor-arg index="0" name="driver" ref="driver" />
        <constructor-arg index="1">
            <value>jdbc:mysql://localhost:3306/test</value>
        </constructor-arg>
        <constructor-arg index="2">
            <value>root</value>
        </constructor-arg>
        <constructor-arg index="3">
            <value>root</value>
        </constructor-arg>
    </bean>
    
    <bean id="userDao" class="constxiong.interview.transaction.UserDaoImpl">
        <property name="dataSource" ref="datasource"></property>
    </bean>
    
    <!-- 事务管理器 -->
    <bean id="tracnsactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"></property>
    </bean>
    
    <tx:advice id="txAdvice" transaction-manager="tracnsactionManager">
        <tx:attributes>
            <!-- 为连接点指定事务属性 -->
            <tx:method name="deleteUser" rollback-for="java.lang.RuntimeException"/>
        </tx:attributes>
    </tx:advice>
    
    <aop:config>
        <!-- 切入点配置 -->
        <aop:pointcut id="point" expression="execution(* *constxiong.interview.transaction.UserDao.deleteUser(..))" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="point"/>
    </aop:config>
    
</beans>

 

测试代码

package constxiong.interview.transaction;
 
import java.util.Map;
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
public class TransactionTest {
 
    static ApplicationContext context = new ClassPathXmlApplicationContext("spring_transaction.xml");
    
    public static void main(String[] args) throws Exception {
        testAspectjTransaction();
    }
    
    
    private static void testAspectjTransaction() {
        UserDao userDao = (UserDao)context.getBean("userDao");
        printUsers(userDao);
        userDao.deleteUser(1);
    }
 
 
    private static void printUsers(UserDao userDao) {
        for (Map<String, Object> user : userDao.getUsers()) {
            System.out.println(user);
        }
    }
 
}

 

输出结果

{id=1, username=user1}
{id=2, username=user2}
Exception in thread "main" java.lang.RuntimeException
    at constxiong.interview.transaction.UserDaoImpl.deleteUser(UserDaoImpl.java:28)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
    at com.sun.proxy.$Proxy2.deleteUser(Unknown Source)
    at constxiong.interview.transaction.TransactionTest.testAnnotationTransaction(TransactionTest.java:20)
    at constxiong.interview.transaction.TransactionTest.main(TransactionTest.java:13)

 

 

PS:

这篇仅用事务回滚为例,了解 spring 事务控制,还需要关注数据库的ACID四种特性、事务传播特性、事务的隔离级别(脏读、不可重复读、幻读)。

详细可参考:https://blog.csdn.net/chinacr07/article/details/78817449

 

spring 事务的源码学习可以参考:

 


  • 基础与语法
    • JDK和JRE有什么区别?
    • ==和equals的区别是什么?
    • 基本类型和包装类对象使用 == 和 equals进行比较的结果?
    • 什么是装箱?什么是拆箱?装箱和拆箱的执行过程?常见问题?
    • hashCode()相同,equals()也一定为true吗?
    • final在java中的作用
    • final finally finalize()区别
    • finally语句块一定执行吗?
    • final与static的区别
    • return与finally的执行顺序对返回值的影响
    • String对象中的replace和replaceAll的区别?
    • Math.round(-1.5) 等于多少?
    • String属于基础的数据类型吗?
    • java中操作字符串都有哪些类?它们之间有什么区别?
    • 如何将字符串反转?
    • String类的常用方法有哪些?
    • 普通类和抽象类有哪些区别?
    • 抽象类必须要有抽象方法吗?
    • 抽象类能使用final修饰吗?
    • 接口和抽象类有什么区别?
    • Java访问修饰符有哪些?权限的区别?
    • Java中的 << >> >>> 是什么?
    • javap的作用是什么?
    • throw和throws的区别?
    • try-catch-finally中哪个部分可以省略?
    • 常见的异常类有哪些?
    • 什么是JAVA内部类?
    • nio中的Files类常用方法有哪些?
    • 什么是反射?有什么作用?
    • 动态代理是什么?应用场景?
    • 怎么实现动态代理?
    • 什么是java序列化?什么情况下需要序列化?
    • 什么场景要对象克隆?
    • 深拷贝和浅拷贝区别是什么?
    • 如何实现对象克隆与深拷贝?
    • Java跨平台运行的原理
    • Java的安全性体现在哪里?
    • Java针对不同的应用场景提供了哪些版本?
    • 什么是JVM?
    • 什么是JDK?
    • 什么是JRE?
    • JDK、JRE、JVM之间的关系是什么样的?
    • Java语言有哪些注释的方式?
    • Java中有几种基本数据类型?它们分别占多大字节?
    • i++和++i的作用和区别
    • &和&&的作用和区别
    • |和||的作用和区别
    • 如何让计算机最高效的算出2乘以8?
    • Java中基本类型的转换规则
    • if-else if-else与switch的区别
    • while和do-while的区别
    • break语句的作用
    • continue语句的作用
    • Java中数组有什么特征?
    • 可变参数的作用和特点是什么?
    • 类和对象的关系
    • 说一说你的对面向过程和面向对象的理解
    • 方法重载和重写是什么?有什么区别?
    • this和super关键字的作用
    • static关键字的作用是什么?
    • abstract关键字的作用是什么?
    • java.lang.Object的常用方法?
    • 子类构造方法的执行过程是什么样的?
    • 什么是Java的多态?
    • instanceof关键字的作用是什么?
    • 什么是Java的垃圾回收机制?
    • 什么是包装类?为什么要有包装类?基本类型与包装类如何转换?
    • 基本类型和包装类的区别?
    • java.sql.Date和java.util.Date的区别
    • 关于Java编译,下面哪一个正确()
    • 关于构造方法,下列说法正确的是()
    • Java接口方法的修饰符可以是()
    • 以下代码将输出()
    • 关于关键字的使用说法错误的是()
    • 关于内存回收正确的是()
    • 哪些标识符合法?
    • 说法正确的是()
    • 定义一个Java类,可被所有类访问,申明正确的是()
    • 说说你对面向对象的理解
    • 内存泄漏和内存溢出的区别
    • 不通过构造方法能创建对象吗?
    • 匿名内部类可以继承类或实现接口吗?为什么?
    • 什么是多态?如何实现?有什么好处?
    • Java中关于继承,错误的是()
    • Math.random()的返回值是多少?
    • 同步代码块和同步方法有什么区别?
    • 静态内部类和非静态内部类有什么区别?
    • 下列运算符合法的是()
    • 打印值是多少?
    • 关于抽象,正确的是()
    • 正确的是()
    • 正确的是()
    • 错误的是()
    • 哪些不能修饰 interface
    • 正确的是()
    • 存在i+1< i的数吗?为什么?
    • 接口可否继承接口?抽象类是否可实现接口?抽象类是否可继承实体类?
    • 可序列化对象为什么要定义serialversionUID值?
    • 十进制100转换成八进制是多少?
    • Class类的getDeclaredFields()与getFields()方法的区别?
    • final修饰变量,是引用不能变?还是引用的对象不能变?
    • 解释以下正则表达式的含义
    • 声明合法的是()
    • 下面打印结果是?
    • Java属于编译型还是解释型语言?
    • 如果有两个类A、B(注意不是接口),如何编写C类同时使用这两个类的功能?
    • 构造方法是否可以被重载?重写?
    • 基本类型byte表示的数值范围是多少?
    • 日期类型如何格式化?字符串如何转日期?
    • 当输入为2的时候返回值是
    • System.out.println('a'+1);的结果是
    • 静态与非静态成员变量区别?
    • 二进制数,小数点向右移一位,值会发生什么变化?
    • 下面两段代码的区别是?
    • switch能否作用在byte、long、String上?
    • 在Java 中,如何跳出当前的多重嵌套循环?
    • 为什么不能根据返回类型来区分方法重载?
    • Inner Class和Static Nested Class的区别?
    • abstract方法是否可是static的?native的?synchronized的?
    • 静态方法能直接调用非静态方法吗?
    • 内部类可以引用它的外部类的成员吗?有什么限制?
    • 打印结果是什么
    • 说说字符串与基本数据之间的转换
    • GB2312编码的字符串如何转换为ISO-8859-1编码?
    • Java中的日期与时间获取与转换?
    • 反射主要实现类有哪些?
    • Class类的作用是什么?如何获取Class对象?
    • 面向对象设计原则有哪些?
    • 反射的使用场景、作用及优缺点?
    • 下面代码的输出是?
    • 关于String[] strArr=new String[10];正确的是()
    • 写一个方法实现String类的replaceAll方法
    • String类是否可以继承?
    • String、StringBuilder、StringBuffer的区别?
    • 为什么String类被设计用final修饰?
    • String s = new String("xyz");创建几个String对象?
    • String s="a"+"b"+"c"+"d";创建了几个对象?
    • 对比一下Java和JavaScriprt
    • 什么是assert?
    • 类的实例化方法调用顺序
    • JDK8中Stream接口的常用方法
    • 说说反射在你实际开发中的使用
    • 什么是泛型?为什么要使用泛型?
    • 有没有使用JDK1.8 中的日期与时间API?
  • 集合
    • java 有哪些常用容器(集合)?
    • ArrayList和Vector的联系和区别
    • Collection和Collections有什么区别?
    • List、Set、Map 之间的区别是什么?
    • HashMap和Hashtable 有什么区别?
    • 如何决定使用HashMap还是TreeMap?
    • ArrayList和LinkedList的区别是什么?
    • Array和ArrayList有何区别?
    • 如何实现数组和List之间的转换?
    • Queue的add()和offer()方法有什么区别?
    • Queue的remove()和poll()方法有什么区别?
    • Queue的element()和peek()方法有什么区别?
    • 哪些集合类是线程安全的?
    • 迭代器Iterator是什么?
    • Iterator怎么使用?有什么特点?
    • Iterator和 ListIterator有什么区别?
    • 怎么确保一个集合不能被修改?
    • 为什么基本类型不能做为HashMap的键值?
    • HashMap的键值需要注意什么?
    • Java中已经数组类型,为什么还要提供集合?
    • TreeSet的原理是什么?使用需要注意什么?
    • HashSet实现原理是什么?有什么特点?
    • 正确的是()
    • HashSet和HashMap有什么区别?
    • ArrayList list=new ArrayList(10);中的list扩容几次?
    • List、Set、Map哪个继承自Collection接口?
    • ArrayList与LinkedList哪个插入性能高?
    • LinkedHashMap、LinkedHashSet、LinkedList哪个最适合当作Stack使用?
    • Map的实现类中,哪些是有序的,哪些是无序的,如何保证其有序性?
    • TreeMap和TreeSet在排序时如何比较元素?
    • Collections工具类中的sort方法如何比较元素?
    • List里如何剔除相同的对象?
    • Java.util.Map的常用实现类有哪些?
    • List、Set、Map 是否继承自 Collection 接口?
    • Vector、ArrayList、LinkedList 的存储性能和特性?
    • List、Map、Set 三个接口,存取元素时,各有什么特点?
    • Map的遍历方式
    • List、Set和Map接口的特点与常用的实现类
    • 说一下HashMap的实现原理
    • ConcurrentHashMap了解吗?说说实现原理。
  • 网络编程
    • java中IO流有哪些?
    • BIO、NIO、AIO有什么区别?
    • tcp和udp的区别?
    • tcp为什么要三次握手,两次不行吗?为什么?
    • tcp粘包是怎么产生的?
    • OSI的七层模型有哪些?
    • 面向字符的输入流是()
    • 如何读取文件a.txt中第10个字节?
    • 关于流的创建,错误的是()
    • JDK中什么类可以通过流写入数据到内存?
    • 如何将字符串写入文件?
    • 输入流和输出流的区别
    • 列举常用字节输入流和输出流
    • 节点流和处理流区别
    • 字节流和字符流区别与适用场景
    • 缓冲流的优缺点
    • Java实现文件夹复制
    • Java中的Socket是什么?
    • 基于TCP和UDP的Socket编程的主要步骤
  • 并发
    • 并行是什么意思?与并发的区别是什么?
    • 什么是线程?什么是进程?为什么要有线程?有什么关系与区别?
    • 什么是守护线程?
    • 如何创建、启动 Java 线程?
    • 什么是并发编程?
    • 为什么要用并发编程?
    • 并发编程的缺点?
    • 导致并发程序出问题的根本原因是什么?
    • Java 程序中怎么保证多线程的运行安全?
    • 如何优雅地停止一个线程?
    • 线程包括哪些状态?状态之间是如何变化的?
    • 什么是线程池?
    • 线程池包含哪些状态?
    • Executors创建线程池有哪几种方式?
    • 如何停止一个线程池?
    • synchronized关键字的作用是什么?
    • volatile关键字的作用是什么?
    • Java中的锁是什么?
    • 锁如何使用?有什么注意事项?
    • 可重入锁与不可重入锁之间的区别与性能差异?
    • Java中的锁之间的区别是什么?
    • synchronized锁的升级原理是什么?
    • 什么是死锁?
    • 如何避免死锁?
    • 什么是活锁和饥饿?
    • Java中有哪些无锁技术来解决并发问题?如何使用?
    • 什么是 Java 内存模型?
    • 什么是 happens-before 原则?
    • sleep()和wait()有什么区别?
    • Runnable和Callable有什么区别?
    • notify()和notifyAll()有什么区别?
    • 线程池中submit()和execute()方法有什么区别?
    • ThreadLocal有什么作用?有哪些使用场景?
    • synchronized和volatile的区别是什么?
    • synchronized和Lock有什么区别?
    • synchronized和ReentrantLock区别是什么?
    • ReadWriteLock如何使用?
    • JDK中Atomic开头的原子类实现原子性的原理是什么?
    • 介绍一下ForkJoinPool的使用
    • LongAdder与AtomicLong有什么区别?
    • 乐观锁与悲观锁是什么?
    • 使用对象的wait()方法需要注意什么?
    • 哪种方式不会使线程进入阻塞状态()
    • volatile关键字能否保证线程安全?
    • 如何保证多个线程同时启动?
    • 同步和异步有何异同,分别在什么情况下使用?
    • 创建进程需要()
    • sleep()和yield()有什么区别?
    • 说说与线程相关的方法
    • 线程的run()方法和start()方法有什么区别?
    • 说说对于sychronized同步锁的理解
    • Java中实现线程通信方式有哪些?
    • 高并发下,如何安全地修改同一行数据?
  • WEB
    • jsp和servlet有什么区别?
    • jsp有哪些内置对象?作用分别是什么?
    • jsp的4种作用域?
    • session和cookie有什么区别?
    • session的工作原理?
    • 客户端禁止cookie,session还能用吗?
    • http响应码301和302代表的是什么?有什么区别?
    • forward和redirect的区别?
    • get和post请求有哪些区别?
    • 如何实现跨域?
    • 什么是JSONP?
    • HTML、CSS、Javascript在Web开发中的作用?
    • body中的onload事件和document.ready()有什么区别?
    • 写一些常见的Javascript正则表达式?
    • Javascript正则表达式使用方式有哪些?
    • jQuery中有哪些选择器?
    • div居中和内容居中的css属性设置
    • JavaScript中null、undefined有什么区别?
    • Servlet中的doPost和doGet方法有什么区别?传递和获取参数上有什么区别?
    • jQuery中get与eq方法的区别
    • 如何配置一个servlet?
    • JavaScript如何定义含有数值1至3的数组?
    • 常见的HTTP协议状态码?
    • servlet的生命周期
    • servlet的常用方法
    • 过滤器的生命周期是什么样的?有什么作用?
    • jquery书写ajax的的方式及参数说明
    • JSP常用的标签
    • 如何防止表单重复提交?
    • 说说什么是JSON?格式是什么样的?
    • 说说Tomcat的模块架构
  • 安全
    • 如何避免sql注入?
    • 什么是XSS攻击,如何避免?
    • 什么是CSRF攻击,如何避免?
  • 设计模式
    • 常用的设计模式有哪些?
    • 简单工厂和抽象工厂有什么区别?
    • 为什么Java中一个类可以实现多个接口,但只能继承一个类?
    • 什么是UML?
    • 什么是单例模式?有什么作用和特点?可以解决哪些问题?懒汉式和饿汉式的区别?如何保证线程安全?
    • 构造方法的参数太多,如何解决?
  • 框架
    • 为什么要使用spring框架?
    • 什么是 AOP?Spring 如何实现的?
    • 什么是 IoC?Spring 如何实现的?
    • spring有哪些主要模块?
    • spring常用的注入方式有哪些?
    • spring中的bean是线程安全的吗?
    • spring支持几种bean的作用域?
    • spring自动装配bean有哪些方式?
    • spring事务实现方式有哪些?
    • 介绍一下spring mvc
    • spring mvc运行流程?
    • spring mvc有哪些组件?
    • @RequestMapping的作用是什么?
    • @Autowired的作用是什么?
    • 什么是spring boot?为什么要用?
    • spring boot核心配置文件是什么?
    • spring boot有哪些方式可以实现热部署?
    • spring中事务的传播特性
    • Spring mvc 与 Spring boot 有什么区别?
    • @Transactional 注解哪些情况下会失效?
    • Spring中ObjectFactory与BeanFactory的区别
    • Spring中BeanFactory.getBean是否线程安全?
    • BeanFactory 和 ApplicationContext 有什么区别?
    • FactoryBean 与 BeanFactory 有什么区别?
    • 介绍一下 Spring bean 的生命周期
    • 介绍一下 Spring 容器的生命周期
    • Spring 如何解决 bean 的循环依赖?
    • Spring Advice 有哪些类型?
    • Spring 的隔离级别
    • Spring AOP 是如何实现的?
    • 如何用 Spring 实现事件驱动编程?
    • 如何用 Spring 实现国际化?
    • 如何用 Spring 加载资源?
    • Spring 如何自定义注解?
    • Spring 框架用到了哪些设计模式?
    • 项目中如何用 Spring 和 Spring MVC 框架的?
  • 数据结构与算法
    • 递归计算n!
    • 什么是递归?递归的优缺点是什么?
    • 什么是复杂度?为什么要进行复杂度分析?
    • 什么是时间复杂度?什么是空间复杂度?
    • 如何进行复杂度分析?
    • 使用递归输出某个目录下所有子目录和文件
    • 常见加密算法有哪些?是否对称?
    • 合并两个有序的链表
    • 单向链表的反转
    • 一个不包含相同元素的整数集合,返回所有可能的不重复子集集合
    • 正确的是()
    • 统计某字符串在文件中出现的次数
    • 统计一段长字符串中某字符串的出现次数
    • 数组与链表的区别
    • 冒泡排序
    • 插入排序(Insertion Sort)
    • 选择排序(Selection Sort)
    • 同样的复杂度,为什么插入排序比冒泡排序更受欢迎?
    • 希尔排序(Shell Sort)
    • 如何理解数组这种数据结构?
    • Java中数组和List的区别
    • Java中如何以链表实现LRU淘汰算法
    • 什么是单向链表?
    • 什么是双向链表?
    • 对比下链表和数组性能
    • 如何理解栈?
    • 如何实现带动态扩容的顺序栈?
    • 如何实现链式栈?
    • 如何理解函数调用栈?
    • 如何应用栈解决表达式求值问题?
  • 异常
    • 列举一些列举常见的运行时异常
    • OutOfMemoryError的原因有哪些?怎么解决?
    • Unsupported major.minor version 52是什么造成的,如何解决?
    • Java中如何进行异常处理?throws、throw、try、catch、finally分别如何使用?
    • 运行时异常与受检异常有何异同?
    • 异常的设计原则有哪些?
    • Java中异常处理机制
  • 文件解析与生成
    • Java中有哪些解析XML的类库?有什么特点?
    • 解析xml的方式有哪些?如何选择?
    • XML文档定义有几种形式?有何区别?
    • XML的使用场景有哪些?
  • linux
    • 什么是Linux?
    • linux如何添加新系统用户?
    • 什么是bash别名?
    • 什么是linux内核?包括哪些模块?
    • linux指令-ls
    • linux指令-cd
    • linux指令-pwd
    • linux指令-mkdir
    • linux指令-rm
    • linux指令-rmdir
    • linux指令-mv
    • linux指令-cp
    • linux指令-cat
    • linux指令-more
    • linux指令-less
    • linux指令-tail
    • linux指令-head
    • linux指令-which
    • linux指令-whereis
    • linux指令-locate
    • linux指令-find
    • linux指令-chmod
    • linux指令-tar
    • linux指令-chown
    • linux指令-df
    • linux指令-du
    • linux指令-ln
    • linux指令-date
    • linux指令-cal
    • linux指令-grep
    • linux指令-wc
    • linux指令-ps
    • linux指令-top
    • linux指令-kill
    • linux指令-free
  • MySQL
    • 如何创建和删除数据库?
    • MyISAM与InnoDB的区别?
    • char与varchar的区别
    • 建表语句中varchar(50)中50的指是什么?
    • int(10)中10指什么?
    • MySQL如何获取当前日期?
    • 如何获取MySQL的版本?
    • 什么是触发器,MySQL都有哪些触发器?
    • MySQL显示表前 50 行
    • 如何连接MySQL服务端、关闭连接?
    • int(10)、char(16)、varchar(16)、datetime、text的意义?
    • 说说你知道的MySQL存储引擎
    • 说一说MySQL中的锁机制
    • 说一说MySQL中的事务
    • MySQL中TEXT数据类型的最大长度
    • MySQL中有哪些时间字段?
    • MySQL中DATETIME和TIMESTAMP的区别
    • MySQL的数据类型有哪些?
    • FLOAT和DOUBLE的区别是什么?
    • Mysql的SQL语句是否区分大小写?
    • Mysql驱动程序是什么?
    • Innodb引擎有什么特性?
    • 使用过MySQL的存储过程吗?介绍一下
    • 什么是索引?什么场景使用?
    • 索引的种类有哪些?
    • 索引如何创建与删除?
    • 索引对性能有哪些影响?
    • MySQL创建和使用索引的注意事项?
    • 创建MySQL联合索引应该注意什么?
    • 列值为NULL时,查询是否会用到索引?
    • 以下语句是否会使用索引?
    • 以下三条sql 如何只建一条索引?
    • LIKE 后的%和_代表什么?
    • 与Oracle相比,Mysql有什么优势?
    • MySQL有哪些常用函数?
    • MyISAM索引与InnoDB索引的区别?
    • Mysql的体系结构是什么样的?
    • Mysql中exists和in的区别
    • MySQL如何进行慢SQL优化?
    • 说一些索引失效的情况
    • 这种情况,ID 是几?
    • 说一说 MySQL 的行锁和表锁
    • 说一说MySQL的乐观锁和悲观锁?
    • 举例说明数据库死锁
    • MySQL中如何避免死锁?
    • MySQL 单表上亿,怎么优化分页查询?
    • MySQL如何配置读写分离?
    • 项目中如何实现读写分离?怎么配置?
    • 如何实现分库分表?怎么配置?
  • Oracle
    • Oracle中function和procedure有什么区别?
    • Oracle中字符串链接符是什么?
    • Oracle怎么分页?
    • rowid与rownum的含义是什么?
    • 如何使用oracle伪列删除表中重复记录?
    • 简述oracle中 dml、ddl、dcl
    • Oracle数据库有哪些触发器?
    • Oracle产生的存储文件有哪些?
    • Oracle存储文件类型的字段?
    • Oracle中排序对性能的影响?
    • data block、extent、segment、tablespace有何区别?
    • 什么是游标?在oracle中如何使用?
    • Oracle怎样实现每天备份一次?
    • oracle中常用的函数
    • 哪些因素影响oracle查询性能?
    • oracle中存储过程、游标、函数的区别?
    • 说说oracle查询性能优化的思路
    • Oracle分区有哪些作用?
    • Oracle数据库如何迁移?
    • Oracle有哪些备份方式?
    • Oracle有哪几种索引?
    • 说说Oracle的导入导出方式?
    • 冷备和热备的优缺点?
  • 数据库
    • truncate和delete的异同?
    • 事务的四大特性
    • 脏读、幻读、不可重复读指什么?
    • 事务有哪些隔离级别?
    • delete、drop、truncate区别
    • 数据库的三范式是什么?有什么作用?
    • 左连接、右连接、内连接和全外连接的区别
  • Redis
    • 介绍一下Redis
    • Redis支持哪些数据类型?
    • Redis有哪些优缺点?
    • Redis与Memcached的区别
    • Redis使用单线程模型为什么性能依然很好?
    • Redis各数据类型最大容量是多少?
    • Redis持久化机制有哪些?各有什么优缺点?
    • Redis使用过程中的注意事项?
    • Redis过期键的删除策略有哪些?
    • 说说Redis的回收策略
    • 为什么Redis所有数据放到内存中?
    • 说说Redis的同步机制?
    • Pipeline有什么好处?
    • 说说Redis集群?
    • 说说遇到的Redis集群方案不可用的情况?
    • 接触过哪些Redis客户端?
    • Redisson、Jedis、Lettuce各有什么优缺点?
    • Redis如何设置密码?
    • Redis哈希槽
    • Redis 集群会有写操作丢失吗?
    • Redis集群之间是如何复制?
    • Redis集群支持最大节点数是多少?
    • Redis如何选择数据库?
    • 怎么测试Redis的连通性?
    • 说一说你对Redis的事务的理解?
    • Redis事务相关的命令有哪些?
    • Redis如何设置过期时间?
    • Redis如何设置永久有效?
    • Redis如何做内存优化?
    • Redis的内存用完了会发生什么?
    • 单个Redis实例最多能存放多少个key?
    • List、Set、Sorted Set最多能存放多少元素?
    • 如何保证Redis中存的都是热点数据?
    • Redis有哪些适用场景?
    • Redis中如何找出已知前缀的key?
    • 处理过大量的key同一时间过期吗?需要注意什么?
    • Redis的队列如何异步使用?
    • Redis如何实现消息一次生产,多次消费?
    • Redis如何实现消息延迟?
    • Redis如何实现分布式锁?
  • Dubbo
    • Dubbo支持哪些协议?各有什么特点?
    • Dubbo如何设置超时时间?
    • 介绍一下Dubbo?
    • Dubbo有些哪些注册中心?
    • Dubbo有哪些负载均衡策略?
    • Dubbo的核心功能?
    • Dubbo的主要作用?
    • Dubbo适用于哪些场景?
    • Dubbo有哪些核心组件?
    • Dubbo服务注册与发现的流程?
    • Dubbo框架分了哪些层?
    • 什么是服务治理?为什么需要服务治理?
    • Dubbo的注册中心挂掉,Consumer和Provider之间还能通讯吗?
    • Dubbo与Spring如何集成?
    • Dubbo有哪些集群容错方案?
    • Dubbo支持哪些序列化方式?
    • 谈谈遇到的Dubbo超时问题
    • Dubbo的安全调用
    • Dubbo和Dubbox之间的关系
    • Dubbo和Spring Cloud的区别
  • JVM
    • 说一说JVM的内存区域
    • JDK8为什么要使用元空间取代永久代?
    • 对象在哪块内存分配?
    • 介绍下Java中垃圾回收机制
    • Java中类加载过程是什么样的?
    • 对象创建过程是什么样的?
    • 方法区内存溢出怎么处理?
    • 谈谈 JVM 中的常量池
    • 谈谈动态年龄判断
    • 谈谈永久代
    • 运行时栈帧包含哪些结构?
    • JVM 的内存模型是什么?
    • JVM 如何确定垃圾对象?
    • 哪些是 GC Roots?
    • 被引用的对象就一定能存活吗?
    • 强引用、软引用、弱引用、虚引用是什么,有什么区别?
    • 你做过 JVM 调优,说说如何查看 JVM 参数默认值?
    • 工作中常用的 JVM 配置参数有哪些?
    • 谈谈对 OOM 的认识
    • 什么情况发生栈溢出?
    • 你有哪些手段来排查 OOM 的问题?
    • 遇到过元空间溢出吗?
    • 遇到过堆外内存溢出吗?
    • 谈谈你知道的垃圾回收算法
    • 谈谈你知道的垃圾收集器
    • 生产环境用的什么JDK?如何配置的垃圾收集器?
    • 如何查看 JVM 当前使用的是什么垃圾收集器?
    • 如何开启和查看 GC 日志?
    • JVM 监控与分析工具你用过哪些?介绍一下。
    • JIT 是什么?
    • 谈谈双亲委派模型
    • 列举一些你知道的打破双亲委派机制的例子。为什么要打破?
    • 说一下垃圾分代收集的过程
    • 如何找到死锁的线程?
    • invokedynamic 指令是干什么的?
    • 什么是方法内联?
    • 什么是逃逸分析?
    • 描述一下什么情况下,对象会从年轻代进入老年代
    • safepoint 是什么?
    • MinorGC、MajorGC、FullGC 什么时候发生?
    • 可以描述一下 class 文件的结构吗?
    • 说说 JVM 如何执行 class 中的字节码
    • 生产环境 CPU 占用过高,你如何解决?
    • 生产环境服务器变慢,如何诊断处理?
  • MQ
    • MQ 是什么?为什么使用?
    • 使用 MQ 的缺陷有哪些?
    • 你了解哪些常用的 MQ?
    • MQ 有哪些使用场景?
    • 如何保证MQ的高可用?
    • 如何保证消息不被重复消费?
    • 如何保证消息不丢失?
    • 如何保证消息的顺序性?
    • 消息大量积压怎么解决?
  • MyBatis
    • 介绍一下 MyBatis
    • Mybaits 的优缺点
    • MyBatis 的适用场景
    • MyBatis 与 Hibernate 的区别
    • #{} 和 ${} 的区别
    • MyBatis 中实体类的属性名与表中的字段名不一致怎么处理?
    • MyBatis 中如何配置连接中断或执行超时?
    • 用 MyBatis 如何使用模糊查询?
    • Mapper 接口如何与写 SQL 的 XML 文件进行绑定的?
    • Mapper 接口方法如何与注解里的 SQL 进行绑定的?
    • Mapper 接口并没有实现类,它是如何工作的?
    • Mapper 接口中能不能根据参数不同进行重载?
    • MyBatis 有哪些分页的方式?分页插件的原理是什么?
    • MyBatis 是如何将 sql 执行结果转换为目标对象并返回的?有哪些映射形式?
    • MyBatis 如何批量插入?
    • MyBatis 如何获取返回自增主键值?
    • Mapper 接口如何传递多个参数?
    • MyBatis 中有哪些动态 SQL 标签?它们的作用分别是什么?如何实现的?
    • Mapper XML 映射文件中支持哪些标签?分别什么作用?
    • 不同 Mapper XML 文件中 id 是否可以相同?
    • 为什么说 MyBatis 是半自动 ORM?
    • MyBatis 如何进行 1对1 和 1对多 的关联查询?
    • 什么是 MyBatis 的接口绑定?有哪些实现方式?
    • MyBatis 的 SQL 执行日志如何开启?
    • MyBatis 中注册 Mapper 有哪些方式?
    • MyBatis 如何支持延迟加载?现实原理是什么?
    • MyBatis 中的本地缓存和二级缓存的作用是什么?怎么实现的?
    • MyBatis 的源码中的核心类有哪些?如何实现框架功能的?
    • MyBatis 如何编写一个自定义插件?
    • MyBatis 插件的运行原理是什么?
    • Spring 中如何配置 MyBatis?
    • MyBatis 是如何与 Spring 集成的?