[Java]Mybatis学习笔记(动力节点老杜)(四)

简介: [Java]Mybatis学习笔记(动力节点老杜)(四)

MyBatis 三大核心对象的作用域

SqlSessionFactoryBuilder

  • 这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。
  • SqlSessionFactoryBuilder 对象的作用就是创建 SqlSessionFactory 对象,只要有了 SqlSessionFactory 对象就不在需要 SqlSessionFactoryBuilder 对象,其就可以被垃圾回收器回收了
  • 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。
static {
    try {
        // 获取默认数据库环境对应的SqlSessionFactory对象
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  • 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。

SqlSessionFactory

  • SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
  • 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。
  • 因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
// 默认数据库环境对应的SqlSessionFactory
private static SqlSessionFactory sqlSessionFactory = null;
static {
    try {
        // 获取默认数据库环境对应的SqlSessionFactory对象
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
    } catch (IOException e) {
        e.printStackTrace();
    }
}

SqlSession

  • 每个线程都应该有它自己的 SqlSession 实例。
  • SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
  • 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。
  • 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。
  • 下面的示例就是一个确保 SqlSession 关闭的标准模式:
try (SqlSession session = sqlSessionFactory.openSession()) {
  // 你的应用逻辑代码
}

使用 javassist 生成类

依赖

<dependencies>
  <!-- javassist -->
  <dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.29.1-GA</version>
  </dependency>
  <!-- junit -->
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
    <scope>test</scope>
  </dependency>
</dependencies>

运行参数配置

  • 出现下列报错,需要进行运行参数的配置,JDK高版本的问题,低版本没有java.base这个模块,但是高版本添加了这个模块
java.lang.reflect.InaccessibleObjectException: 
Unable to make protected final java.lang.Class 
java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) 
throws java.lang.ClassFormatError accessible: 
module java.base does not "opens java.lang" to unnamed module @28c97a5
  • –add-opens java.base/java.lang=ALL-UNNAMED
  • –add-opens java.base/sun.net.util=ALL-UNNAMED

Javassist的使用

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import java.lang.reflect.Method;
/**
 * ClassName: Test
 * Package: PACKAGE_NAME
 * Description:
 *
 * @Author tcw
 * @Create 2023-05-31 15:54
 * @Version 1.0
 */
public class Test {
    @org.junit.Test
    public void tset01() throws Exception {
        // 获取类池,用于生成class
        ClassPool pool = ClassPool.getDefault();
        // 使用类池制造类
        // 方法参数为类的全类名
        CtClass ctClass = pool.makeClass("cw.mybatis.bank.dao.impl.AccountDaoImpl");
        // 类中方法的代码
        String methodCode = "public void insert() { System.out.println(\"数据库正在新增信息...\");}";
        // 制造类中的方法
        // 参数一:类中方法的代码;参数二:为哪个类创建方法
        CtMethod ctMethod = CtMethod.make(methodCode, ctClass);
        // 将创建的方法添加到类中
        ctClass.addMethod(ctMethod);
        // 在内存中动态生成class,将类加载到JVM中
        // 得到类对应的Class对象
        // Class<?> aClass = ctClass.toClass();
        ctClass.toClass();
        // 加载类到JVM中
        Class<?> aClass = Class.forName("cw.mybatis.bank.dao.impl.AccountDaoImpl");
        // 利用动态生成的类进行对象的创建(使用无参构造方法)
        Object o = aClass.getDeclaredConstructor().newInstance();
        // 获取类中的方法
        Method insertMethod = aClass.getDeclaredMethod("insert");
        // 调用新创建的对象的insert方法
        insertMethod.invoke(o);
    }
}

使用 javassist 动态生成类并实现接口

public interface AccountDao {
    void delete();
}
@org.junit.Test
public void testGenerateImpl() throws Exception {
    // 获取类型用于类的制造
    ClassPool pool = ClassPool.getDefault();
    // 制造类
    CtClass AccountDaoImpl = pool.makeClass("cw.study.mybatis.dao.impl.AccountDaoImpl");
    // 制造接口
    CtClass AccountDao = pool.makeInterface("cw.study.mybatis.dao.AccountDao");
    // 添加接口到类中
    AccountDaoImpl.addInterface(AccountDao);
    // 实现接口中的方法
    // 方法的代码
    String methodCode = "public void delete() {System.out.println(\"数据库正在删除信息...\");}";
    // 制造AccountDaoImpl类的方法
    CtMethod method = CtMethod.make(methodCode, AccountDaoImpl);
    // 将方法添加到类中
    AccountDaoImpl.addMethod(method);
    // 在内存中生成类,并将类加载到JVM中
    Class<?> AccountDaoImplClass = AccountDaoImpl.toClass();
    // 创建对象
    AccountDao accountDao = (AccountDao) AccountDaoImplClass.getDeclaredConstructor().newInstance();
    // 调用方法
    accountDao.delete();
}

使用 javassist 动态生成类并实现接口中所有方法

public interface AccountDao {
    void delete();
    int insert(String actno);
    int update(String actno, Double balance);
    String selectByActno(String actno);
}
@org.junit.Test
public void testGenerateAccountDaoImpl() throws Exception {
    // 获取类池
    ClassPool pool = ClassPool.getDefault();
    // 制造类
    CtClass ctClass = pool.makeClass("cw.study.mybatis.dao.impl.AccountDaoImpl");
    // 制造接口
    CtClass ctInterface = pool.makeInterface("cw.study.mybatis.dao.AccountDao");
    // 类实现接口
    ctClass.addInterface(ctInterface);
    // 获取接口中的所有方法
    Method[] methods = AccountDao.class.getDeclaredMethods();
    // 遍历接口中的每个方法实现接口方法
    Arrays.stream(methods).forEach(method -> {
        // 实现接口方法
        // public void update(String actno, Double balance) {}
        StringBuilder builder = new StringBuilder();
        // 添加访问权限修饰符
        builder.append("public ");
        // 添加返回值类型
        builder.append(method.getReturnType().getName());
        builder.append(" ");
        // 追加方法名
        builder.append(method.getName());
        builder.append("(");
        // 获取方法的形参列表
        Parameter[] parameters = method.getParameters();
        // 遍历追加形参列表
        for (int i = 0; i < parameters.length; i++) {
            // 追加形参列表中形参的类型
            builder.append(parameters[i].getType().getName());
            builder.append(" ");
            // 追加形参名 parameters[i].getName() 获取的形参名为 arg0 arg1 ...
            builder.append(parameters[i].getName());
            if (i != parameters.length - 1) {
                builder.append(", ");
            }
        }
        builder.append(") {");
        // 添加方法体的方法
        builder.append("System.out.println(\"" + method.getName() + "\");");
        // 动态添加return语句
        // 获取返回类型的简类名
        String returnTypeSimpleName = method.getReturnType().getSimpleName();
        if ("void".equals(returnTypeSimpleName)) {
        } else if ("int".equals(returnTypeSimpleName)) {
            builder.append("return 111;");
        } else if ("String".equals(returnTypeSimpleName)) {
            builder.append("return \"method return string\";");
        }
        builder.append("}");
        // System.out.println(builder);
        try {
            // 制造ctClass的方法
            CtMethod method1 = CtMethod.make(builder.toString(), ctClass);
            // 将方法添加到类中
            ctClass.addMethod(method1);
        } catch (CannotCompileException e) {
            e.printStackTrace();
        }
    });
    // 在内存中生成类并将类加载到JVM
    Class<?> aClass = ctClass.toClass();
    // 创建对象(接口的实现类可以进行强转)
    AccountDao accountDao = (AccountDao) aClass.getDeclaredConstructor().newInstance();
    // 调用方法
    accountDao.delete();
    accountDao.insert("");
    accountDao.selectByActno("");
    accountDao.update("", 12.0);
}

工具类 GenerateDaoProxy 的实现

  • 工具类 GenerateDaoProxy 可以动态生成接口的实现类
  • 在MyBatis中对javassist进行了二次包装,所以可以在MyBatis中直接使用javassist
  • 由于SQL语句的id是框架的使用者提供的,所以框架的开发者不可能知道SQL语句的id,因此框架的开发者就规定SQL语句的id必须时dao接口中的方法名,namespace必须是dao接口的全限定类名,否则不能使用框架提供的动态代理生成接口的实现类的功能
package cw.study.mybatis.utils;
import org.apache.ibatis.javassist.CannotCompileException;
import org.apache.ibatis.javassist.ClassPool;
import org.apache.ibatis.javassist.CtClass;
import org.apache.ibatis.javassist.CtMethod;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.session.SqlSession;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
/**
 * ClassName: GenerateDaoProxy
 * Package: cw.study.mybatis.utils
 * Description:
 * 该工具类用于动态生成实现Dao接口的代理类
 * GenerateDaoProxy 这个工具类是MyBatis框架提供的
 *
 * @Author tcw
 * @Create 2023-05-31 17:42
 * @Version 1.0
 */
public class GenerateDaoProxy {
    /**
     * 工具类的构造方法私有化,防止创建对象
     */
    private GenerateDaoProxy() {}
    /**
     * 动态生成Dao接口的代理类对象
     *
     * @param sqlSession 与数据库的会话对象,由工具类的使用这传递
     * @param daoInterfaceClass Dao接口
     * @return Dao接口的代理类对象
     */
    public static Object generate(SqlSession sqlSession, Class daoInterfaceClass) {
        // 获取类池
        ClassPool pool = ClassPool.getDefault();
        // 制造接口的代理类
        CtClass daoInterfaceImpl = pool.makeClass(daoInterfaceClass.getName() + "Impl");
        // 制造接口
        CtClass daoInterface = pool.makeInterface(daoInterfaceClass.getName());
        // 接口的代理类实现接口
        daoInterfaceImpl.addInterface(daoInterface);
        // 接口的代理类实现接口中的方法
        // 获取接口中所有的方法
        Method[] daoInterfaceClassDeclaredMethods = daoInterfaceClass.getDeclaredMethods();
        // 遍历接口中的所有的方法,逐个进行实现,并添加到接口的代理类中
        Arrays.stream(daoInterfaceClassDeclaredMethods).forEach(method -> {
            // 实现接口中的方法
            try {
                // 接口方法的实现方法的代码
                StringBuilder methodCode = new StringBuilder();
                // public int update(String actno, Double balance) {代码;}
                methodCode.append("public ");
                // 获取接口方法的返回值类型,添加到实现方法中
                methodCode.append(method.getReturnType().getName());
                methodCode.append(" ");
                // 获取接口方法的方法名,添加到实现方法中
                methodCode.append(method.getName());
                methodCode.append("(");
                // 获取接口方法的形参列表,添加到实现方法中
                Parameter[] methodParameters = method.getParameters();
                for (int i = 0; i < methodParameters.length; i++) {
                    // 获取形参的类型
                    methodCode.append(methodParameters[i].getType().getName());
                    methodCode.append(" ");
                    // 获取形参的名 arg0 arg1 arg2 ...
                    methodCode.append(methodParameters[i].getName());
                    // 如果不是最后一个形参需要在后面添加逗号
                    if (i != methodParameters.length - 1) {
                        methodCode.append(", ");
                    }
                }
                methodCode.append(")");
                methodCode.append("{\n");
                // 接口方法的具体实现
                // 获取与数据库的会话对象
                // javassist 需要知道类是哪个包下的所以要使用全限定包名
                methodCode.append("\torg.apache.ibatis.session.SqlSession sqlSession = cw.study.mybatis.utils" +
                                ".SqlSessionUtil.openSession();\n");
                // 执行SQL语句,我们需要知道SQL语句的类型才可以调用相应的方法执行SQL
                // getConfiguration() 获取MyBatis核心配置文件中根标签configuration中的内容
                // getMappedStatement(SQL语句的Id) 根据SQL语句的id获取相应的SQL语句
                // getSqlCommandType() 获取SQL语句的类型,获取到SQL语句的类型是一个枚举值
                // 由于SQL语句的id是框架的使用者提供的,所以框架的开发者不可能知道SQL语句的id
                // 因此框架的开发者就规定SQL语句的id必须时dao接口中的方法名,namespace必须是dao接口的全限定类名
                // 否则不能使用框架提供的动态代理生成接口的实现类的功能
                // SQL id = namespace + . +SQL id
                String SqlId = daoInterfaceClass.getName() + "." + method.getName();
                SqlCommandType sqlCommandType = sqlSession.getConfiguration().getMappedStatement(SqlId).getSqlCommandType();
                // 根据SQL语句的类型的不同调用相应的方法
                if (sqlCommandType == SqlCommandType.INSERT) {
                } else if (sqlCommandType == SqlCommandType.DELETE) {
                } else if (sqlCommandType == SqlCommandType.UPDATE) {
                    methodCode.append("\treturn sqlSession.update(\"" + SqlId + "\", arg0);\n");
                } else if (sqlCommandType == SqlCommandType.SELECT) {
                    // by java.lang.reflect.InvocationTargetException
                    methodCode.append("\treturn (" + method.getReturnType().getName() + ") sqlSession.selectOne(\"" + SqlId +
                            "\", arg0);\n");
                }
                methodCode.append("}");
                // System.out.println(methodCode);
                // 制造接口方法对应的实现方法
                CtMethod ctMethod = CtMethod.make(methodCode.toString(), daoInterfaceImpl);
                // 将制造的实现方法添加到动态生成的代理类中
                daoInterfaceImpl.addMethod(ctMethod);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        // 接口动态代理类的对象
        Object daoInterfaceProxyObj = null;
        try {
            // 在内存中动态生成类,并且将动态生成的类添加到JVM中
            Class<?> daoInterfaceImplClass = daoInterfaceImpl.toClass();
            // 创建接口代理类的对象
            daoInterfaceProxyObj = daoInterfaceImplClass.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 返回接口动态代理类的对象
        return daoInterfaceProxyObj;
    }
}

工具类 GenerateDaoProxy 测试

  • 要想使用工具类GenerateDaoProxy这种自动生成Dao接口实现类的机制: namespace必须是dao接口的全限定名称,id必须是dao接口的方法名。
<!-- mybatis -->
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>3.5.10</version>
</dependency>
<!-- mysql -->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>8.0.30</version>
</dependency>
<!-- junit -->
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.13.2</version>
  <scope>test</scope>
</dependency>
package cw.study.mybatis.pojo;
/**
 * ClassName: Account
 * Package: cw.study.mybatis.pojo
 * Description:
 *
 * @Author tcw
 * @Create 2023-05-28 14:33
 * @Version 1.0
 */
public class Account {
    private Long id;
    private String actno;
    private Double balance;
    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", actno='" + actno + '\'' +
                ", balance=" + balance +
                '}';
    }
    public Account() {
    }
    public Account(Long id, String actno, Double balance) {
        this.id = id;
        this.actno = actno;
        this.balance = balance;
    }
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getActno() {
        return actno;
    }
    public void setActno(String actno) {
        this.actno = actno;
    }
    public Double getBalance() {
        return balance;
    }
    public void setBalance(Double balance) {
        this.balance = balance;
    }
}
package cw.study.mybatis.dao;
import cw.study.mybatis.pojo.Account;
/**
 * ClassName: AccountDao
 * Package: cw.study.mybatis.dao
 * Description:
 *
 * @Author tcw
 * @Create 2023-05-31 16:44
 * @Version 1.0
 */
public interface AccountDao {
    Account selectByActno(String actno);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cw.study.mybatis.dao.AccountDao">
  <select id="selectByActno" resultType="cw.study.mybatis.pojo.Account">
    select * from t_act where actno = #{actno}
  </select>
</mapper>
@org.junit.Test
public void testGenerateDaoProxy() {
    SqlSession sqlSession = SqlSessionUtil.openSession();
    AccountDao accountDao = (AccountDao) GenerateDaoProxy.generate(sqlSession, AccountDao.class);
    Account act001 = accountDao.selectByActno("act001");
    System.out.println(act001);
}

MyBatis 的 getMapper 方法(MyBatis 的接口代理机制)

  • 在MyBatis中提供了相关机制,可以为我们动态生成dao接口的代理实现类,即工具类 GenerateDaoProxy 不用我们编写
  • MyBatis中实际上采用了代理机制,在内存中生成dao接口的代理实现类,并创建代理类的实例对象
  • 如果要使用MyBatis提供的dao接口代理机制,SQL语句的id必须时dao接口中的方法名,namespace必须是dao接口的全限定类名
  • MyBatis提供的dao接口代理机制的使用如下:
@org.junit.Test
public void testGetMapper() {
    SqlSession sqlSession = SqlSessionUtil.openSession();
    // GenerateDaoProxy.generate(sqlSession, AccountDao.class);
    // 需要一个sqlSession用于获取SQL id,AccountDao.class 需要代理实现的接口
    // sqlSession.getMapper(AccountDao.class)
    // 调用该方法的就是用于获取SQL id的sqlSession,AccountDao.class 需要代理实现的接口
    // 该方法返回dao接口的代理实现类对象实例
    // 要使用该方法,SQL语句的id必须时dao接口中的方法名,namespace必须是dao接口的全限定类名
    AccountDao accountDaoProxy = sqlSession.getMapper(AccountDao.class);
    Account act001 = accountDaoProxy.selectByActno("act001");
    System.out.println(act001);
}

面向接口进行CRUD

工具类 SqlSessionUtil

package cw.mybatis.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
/**
 * ClassName: SqlSessionUtil
 * Package: cw.mybatis.utils
 * Description:
 *
 * @Author tcw
 * @Create 2023-05-23 21:40
 * @Version 1.0
 */
public class SqlSessionUtil {
    private static SqlSessionFactory sqlSessionFactory = null; // 默认使用数据库环境对应的SqlSessionFactory
    private static ThreadLocal<SqlSession> local = new ThreadLocal<>(); // 保证一个线程对应一个SqlSession
    static {
        try {
            // 获取默认使用数据库环境对应的SqlSessionFactory对象
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config" +
                    ".xml"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 私有化构造器,防止创建工具类实例对象
     */
    private SqlSessionUtil() {}
    /**
     * 使用工厂对象开启本线程和数据库的会话
     *
     * @return 与数据库的会话对象
     */
    public static SqlSession openSession() {
        SqlSession sqlSession = local.get(); // 获取当前线程对应的数据库会话对象
        // 如果当前线程没有对应的数据库会话对象,则创建一个会话对象
        if (sqlSession == null) {
            sqlSession = sqlSessionFactory.openSession();
            // 保存本线程对应的数据库会话对象
            // 将sqlSession对象绑定到当前线程上。
            local.set(sqlSession);
        }
        return sqlSession;
    }
    /**
     * 关闭会话对象
     * 关闭SqlSession对象并从当前线程中移除SqlSession对象
     */
    public static void close() {
        SqlSession sqlSession = local.get(); // 获取当前线程对应的数据库会话对象
        // 如果当前线程有相应的数据库会话对象就进行关闭
        if (sqlSession != null) {
            sqlSession.close();
            // 注意移除SqlSession对象和当前线程的绑定关系。
            // 因为Tomcat服务器支持线程池。也就是说:用过的线程对象t1,可能下一次还会使用这个t1线程。
            local.remove();
        }
    }
}

Car(pojo)

package cw.mybatis.pojo;
/**
 * ClassName: Car
 * Package: cw.mybatis.pojo
 * Description:
 * 封装汽车相关信息的pojo类,普通的java类。
 *
 * @Author tcw
 * @Create 2023-05-23 21:59
 * @Version 1.0
 */
public class Car {
    private Long id;
    private String carNum;
    private String brand;
    private Double guidePrice;
    private String produceTime;
    private String carType;
    public Car() {
    }
    public Car(Long id, String carNum, String brand, Double guidePrice, String produceTime, String carType) {
        this.id = id;
        this.carNum = carNum;
        this.brand = brand;
        this.guidePrice = guidePrice;
        this.produceTime = produceTime;
        this.carType = carType;
    }
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getCarNum() {
        return carNum;
    }
    public void setCarNum(String carNum) {
        this.carNum = carNum;
    }
    public String getBrand() {
        return brand;
    }
    public void setBrand(String brand) {
        this.brand = brand;
    }
    public Double getGuidePrice() {
        return guidePrice;
    }
    public void setGuidePrice(Double guidePrice) {
        this.guidePrice = guidePrice;
    }
    public String getProduceTime() {
        return produceTime;
    }
    public void setProduceTime(String produceTime) {
        this.produceTime = produceTime;
    }
    public String getCarType() {
        return carType;
    }
    public void setCarType(String carType) {
        this.carType = carType;
    }
    @Override
    public String toString() {
        return "Car{" + "id=" + id + ", carNum='" + carNum + '\'' + ", brand='" + brand + '\'' + ", guidePrice=" + guidePrice + ", produceTime='" + produceTime + '\'' + ", carType='" + carType + '\'' + '}';
    }
}

CarMapper

  • 操作数据库的接口,在MyBatis中一般包名命名为mapper,就是MVC架构模式中的dao
  • 在MyBatis中操作数据库的接口名,一般叫XxxxMapper,而不为XxxxDao
package cw.mybatis.mapper;
import cw.mybatis.pojo.Car;
import java.util.List;
/**
 * ClassName: CarMapper
 * Package: cw.mybatis.mapper
 * Description:
 *
 * @Author tcw
 * @Create 2023-05-23 21:57
 * @Version 1.0
 */
public interface CarMapper {
    /**
     * 新增 car
     * 
     * @param car 需要新增的 car 信息
     * @return 影响数据库中的条数
     */
    int insert(Car car);
    /**
     * 根据 id 删除汽车信息
     * 
     * @param id 汽车信息对应的 id
     * @return 影响数据库中的条数
     */
    int deleteById(Long id);
    /**
     * 修改汽车信息
     * 
     * @param car 修改之后的汽车信息
     * @return 影响数据库中的条数
     */
    int update(Car car);
    /**
     * 根据汽车 id 查询汽车信息
     * 
     * @param id 汽车信息的 id
     * @return 汽车信息
     */
    Car selectById(Long id);
    /**
     * 查询所有的汽车信息
     * 
     * @return 所有的汽车信息
     */
    List<Car> selectAll();
}

CarMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 如果要使用面向接口的方式进行CRUD,则namespace的属性值必须为相应接口的全类名 -->
<!-- SQL语句的id必须为方法名 -->
<mapper namespace="cw.mybatis.mapper.CarMapper">
  <insert id="insert">
    insert into t_car values(null, #{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
  </insert>
  <delete id="deleteById">
    delete from t_car where id = #{id}
  </delete>
  <update id="update">
    update t_car set
                   car_num=#{carNum},
                   brand=#{brand},
                   guide_price=#{guidePrice},
                   produce_time=#{produceTime},
                   car_type=#{carType}
    where id = #{id}
  </update>
  <select id="selectById" resultType="cw.mybatis.pojo.Car">
    select
      id,
      car_num as carNum,
      brand,
      guide_price as guidePrice,
      produce_time as produceTime,
      car_type as carType
    from t_car where id = #{id}
  </select>
  <select id="selectAll" resultType="cw.mybatis.pojo.Car">
    select
      id,
      car_num as carNum,
      brand,
      guide_price as guidePrice,
      produce_time as produceTime,
      car_type as carType
    from t_car
  </select>
</mapper>

测试

package cw.mybatis.mapper;
import cw.mybatis.pojo.Car;
import cw.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
import static org.junit.Assert.*;
/**
 * ClassName: CarMapperTest
 * Package: cw.mybatis.mapper
 * Description:
 *
 * @Author tcw
 * @Create 2023-05-23 22:15
 * @Version 1.0
 */
public class CarMapperTest {
    @Test
    public void insert() {
        SqlSession sqlSession = SqlSessionUtil.openSession();
        // 面向接口,获取接口的代理对象
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        // 数据对应的对象
        Car car = new Car(null, "4444", "奔驰C200", 32.0, "2000-10-10", "新能源");
        // 调用定义的新增car的方法
        int insert = mapper.insert(car);
        System.out.println(insert);
        sqlSession.commit();
        SqlSessionUtil.close();
    }
    @Test
    public void deleteById() {
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        int i = mapper.deleteById(1L);
        System.out.println(i);
        sqlSession.commit();
        SqlSessionUtil.close();
    }
    @Test
    public void update() {
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Car car = new Car(20L, "4444", "奔驰C200&&&", 32.0, "2000-10-10", "新能源");
        int update = mapper.update(car);
        System.out.println(update);
        sqlSession.commit();
        SqlSessionUtil.close();
    }
    @Test
    public void selectById() {
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Car car = mapper.selectById(20L);
        System.out.println(car);
        SqlSessionUtil.close();
    }
    @Test
    public void selectAll() {
        SqlSession sqlSession = SqlSessionUtil.openSession();
        List<Car> cars = sqlSession.getMapper(CarMapper.class).selectAll();
        cars.forEach(System.out::println);
        SqlSessionUtil.close();
    }
}


相关文章
|
2月前
|
Java 数据库连接 Maven
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和MyBatis Generator,使用逆向工程来自动生成Java代码,包括实体类、Mapper文件和Example文件,以提高开发效率。
146 2
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
|
2月前
|
搜索推荐 Java 数据库连接
Java|在 IDEA 里自动生成 MyBatis 模板代码
基于 MyBatis 开发的项目,新增数据库表以后,总是需要编写对应的 Entity、Mapper 和 Service 等等 Class 的代码,这些都是重复的工作,我们可以想一些办法来自动生成这些代码。
39 6
|
1月前
|
Java 数据库连接 API
Spring 框架的介绍(Java EE 学习笔记02)
Spring是一个由Rod Johnson开发的轻量级Java SE/EE一站式开源框架,旨在解决Java EE应用中的多种问题。它采用非侵入式设计,通过IoC和AOP技术简化了Java应用的开发流程,降低了组件间的耦合度,支持事务管理和多种框架的无缝集成,极大提升了开发效率和代码质量。Spring 5引入了响应式编程等新特性,进一步增强了框架的功能性和灵活性。
47 0
|
3月前
|
缓存 前端开发 Java
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
Soring Boot的起步依赖、启动流程、自动装配、常用的注解、Spring MVC的执行流程、对MVC的理解、RestFull风格、为什么service层要写接口、MyBatis的缓存机制、$和#有什么区别、resultType和resultMap区别、cookie和session的区别是什么?session的工作原理
|
3月前
|
存储 安全 Java
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(进阶篇)
本文是Java基础的进阶篇,对异常、集合、泛型、Java8新特性、I/O流等知识进行深入浅出的介绍,并附有对应的代码示例,重要的地方带有对性能、底层原理、源码的剖析。适合Java初学者。
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(进阶篇)
|
2月前
|
Java 数据安全/隐私保护
java学习笔记(基础习题)
java学习笔记(基础习题)
44 0
|
2月前
|
Java 程序员 开发工具
java学习笔记
java学习笔记
46 0
|
3月前
|
Java 数据库连接 数据格式
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit
IOC/DI配置管理DruidDataSource和properties、核心容器的创建、获取bean的方式、spring注解开发、注解开发管理第三方bean、Spring整合Mybatis和Junit
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit
|
3月前
|
存储 安全 Java
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(高级篇)
本文是“Java学习路线”中Java基础知识的高级篇,主要对多线程和反射进行了深入浅出的介绍,在多线程部分,详细介绍了线程的概念、生命周期、多线程的线程安全、线程通信、线程同步,并对synchronized和Lock锁;反射部分对反射的特性、功能、优缺点、适用场景等进行了介绍。
|
1天前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
11 3