1、什么是 Javassist ?
是一个开源的分析、编辑和创建Java字节码的类库。已加入了开放源代码JBoss 应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态"AOP"框架。
说的明白一点就是:为我们生成类的。
2、我们为什么要使用它呢?我们自己手动创建一个类不是很方便吗?
package com.powernode.bank.dao.impl;
import com.powernode.bank.dao.AccountDao;
import com.powernode.bank.pojo.Account;
import com.powernode.bank.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
/**
* @author Bonbons
* @version 1.0
*/
public class AccountDaoImpl implements AccountDao {
@Override
public Account selectByActno(String actno) {
//开启会话,根据actno查询账户
SqlSession sqlSession = SqlSessionUtil.openSession();
Account account = (Account) sqlSession.selectOne("com.powernode.bank.dao.AccountDao.selectByActno",actno);
// 关闭会话,返回账户信息
// sqlSession.close();
return account;
}
@Override
public int updateActno(Account act) {
//开启会话
SqlSession sqlSession = SqlSessionUtil.openSession();
//修改余额
int count = sqlSession.update("com.powernode.bank.dao.AccountDao.updateActno", act);
// //提交事务,关闭会话
// sqlSession.commit();
// sqlSession.close();
//返回影响数据库表中记录的条数
return count;
}
}
这部分代码简单,而且没有多少内容,所以我们就像不去写这个类,而是通过Javassist去实现直接在内存中生成类。
1、我们需要在模块中导入 javassist 的依赖 【mybatis、junit依赖也需要】
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.29.1-GA</version>
</dependency>
2、我们这部分的目的就是 >> 为我们数据库操作接口生成类
(1)写一下 dao 层的接口 AccoutDao 【增删改查四个操作】
package com.powernode.bank.dao;
/**
* @author Bonbons
* @version 1.0
*/
public interface AccountDao {
void delete();
int update(String actno, double balance);
int insert(String actno);
String selectByActno(String actno);
}
(2)接下来就可以写我们的 javassist 类了 JavassistTest【由浅入深该类中有三个 @Test】
package com.powernode.javassist;
import com.powernode.bank.dao.AccountDao;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import org.junit.Test;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* @author Bonbons
* @version 1.0
*/
public class JavassistTest {
@Test
public void testGenerateImpl() throws Exception{
// 获取类池
ClassPool pool = ClassPool.getDefault();
// 制造类
CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
// 制造接口
CtClass ctInterface = pool.makeInterface("com.powernode.bank.dao.AccountDao");
// 将接口添加到类中[类似声明类实现哪个接口]
ctClass.addInterface(ctInterface);
// 实现接口中的方法
// (1)制造方法
CtMethod ctMethod = CtMethod.make("public void delete(){System.out.println(\"hello delete!\");}", ctClass);
// (2)将方法添加到类中
ctClass.addMethod(ctMethod);
// 在内存中生成类,并将类加载到JVM中
Class<?> clazz = ctClass.toClass();
AccountDao accountDao = (AccountDao)clazz.newInstance();
accountDao.delete();
}
@Test
public void testGenerateFirstClass() throws Exception{
// 获取类池,通过类池的实例创建Class
ClassPool pool = ClassPool.getDefault();
// 根据指定的类名创建类
CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
// 创建方法
String methodCode = "public void insert(){System.out.println(123);}";
CtMethod ctMethod = CtMethod.make(methodCode,ctClass);
// 将我们创建的方法添加到我们创建的类中
ctClass.addMethod(ctMethod);
// 在内存中生成Class
ctClass.toClass();
// 至此,javassist的任务已经完成了 >> 在内存中生成类
// 为了使用这个类和方法。我们添加一些JDK中的方法
// 类加载到JVM中,返回类的字节码
Class<?> clazz = Class.forName("com.powernode.bank.dao.impl.AccountDaoImpl");
// 创建类的实例
Object obj = clazz.newInstance();
//获取它的insert方法
Method insertMethod = clazz.getDeclaredMethod("insert");
//调用这个方法
insertMethod.invoke(obj);
}
// 动态的实现接口中的方法
@Test
public void testGenerateAccountDaoImpl() throws Exception{
// 获取类池
ClassPool pool = ClassPool.getDefault();
// 制造类
CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
// 制造接口
CtClass ctInterface = pool.makeInterface("com.powernode.bank.dao.AccountDao");
// 实现接口[只有类实现了接口,最后才能强转Wie接口的类型]
ctClass.addInterface(ctInterface);
// 获取接口中所有的方法
Method[] methods = AccountDao.class.getDeclaredMethods();
// 流式遍历
Arrays.stream(methods).forEach(method -> {
// method 是接口中的抽象方法,我们现在要实现这些方法
try {
// 创建我们要拼接的方法
StringBuilder methodCode = new StringBuilder();
// 追加修饰符列表
methodCode.append("public ");
// 追加返回值类型
methodCode.append(method.getReturnType().getName());
// 追加空格
methodCode.append(" ");
// 追加方法名
methodCode.append(method.getName());
// 追加左括号
methodCode.append("(");
// 拼接参数列表:(1)先获得所有返回值类型
Class<?>[] parameterTypes = method.getParameterTypes();
// 遍历数组
for (int i = 0; i < parameterTypes.length; i++) {
// 获取当前参数类型
Class<?> parameterType = parameterTypes[i];
// 拼接当前的参数类型
methodCode.append(parameterType.getName());
// 拼接空格
methodCode.append(" ");
// 拼接参数名
methodCode.append("arg" + i);
// 不是参数列表最后一个元素,都要拼接一个逗号
if(i != parameterTypes.length - 1){
methodCode.append(",");
}
}
//追加一条输出语句
methodCode.append("){System.out.println(1111);");
// 判断当前方法的返回值类型
String returnTypeSimpleName = method.getReturnType().getSimpleName();
// 分情讨论 [我们接口这块只有 void、String、double]
if("void".equals(returnTypeSimpleName)){
// 不返回
}else if("int".equals(returnTypeSimpleName)){
methodCode.append("return 1;");
}else if("String".equals(returnTypeSimpleName)){
methodCode.append("return \"hello\";");
}
// 添加结束右括号
methodCode.append("}");
System.out.println(methodCode);
CtMethod ctMethod = CtMethod.make(methodCode.toString(), ctClass);
ctClass.addMethod(ctMethod);
} catch (Exception e) {
e.printStackTrace();
}
});
// 在内存中生成class,并且添加到JVM中
Class<?> clazz = ctClass.toClass();
// 创建对象
AccountDao accountDao = (AccountDao) clazz.newInstance();
// 调用方法
accountDao.insert("bala");
accountDao.delete();
accountDao.update("bala", 1000.0);
accountDao.selectByActno("bala");
}
}
3、第一个 @Test 的内容
@Test
public void testGenerateFirstClass() throws Exception{
// 获取类池,通过类池的实例创建Class
ClassPool pool = ClassPool.getDefault();
// 根据指定的类名创建类
CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
// 创建方法
String methodCode = "public void insert(){System.out.println(123);}";
CtMethod ctMethod = CtMethod.make(methodCode,ctClass);
// 将我们创建的方法添加到我们创建的类中
ctClass.addMethod(ctMethod);
// 在内存中生成Class
ctClass.toClass();
// 至此,javassist的任务已经完成了 >> 在内存中生成类
// 为了使用这个类和方法。我们添加一些JDK中的方法
// 类加载到JVM中,返回类的字节码
Class<?> clazz = Class.forName("com.powernode.bank.dao.impl.AccountDaoImpl");
// 创建类的实例
Object obj = clazz.newInstance();
//获取它的insert方法
Method insertMethod = clazz.getDeclaredMethod("insert");
//调用这个方法
insertMethod.invoke(obj);
}
4、第二个 @Test 的内容
@Test
public void testGenerateImpl() throws Exception{
// 获取类池
ClassPool pool = ClassPool.getDefault();
// 制造类
CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
// 制造接口
CtClass ctInterface = pool.makeInterface("com.powernode.bank.dao.AccountDao");
// 将接口添加到类中[类似声明类实现哪个接口]
ctClass.addInterface(ctInterface);
// 实现接口中的方法
// (1)制造方法
CtMethod ctMethod = CtMethod.make("public void delete(){System.out.println(\"hello delete!\");}", ctClass);
// (2)将方法添加到类中
ctClass.addMethod(ctMethod);
// 在内存中生成类,并将类加载到JVM中
Class<?> clazz = ctClass.toClass();
AccountDao accountDao = (AccountDao)clazz.newInstance();
accountDao.delete();
}
这是一个最简单的 javassist 应用案例,它的使用流程与注释步骤基本相同
获取类池 >> 制造类 >> 制造接口 >> 用类去实现接口 >> 创建方法 >> 将方法添加到类中
5、第三个 @Test 的内容 【动态的获取接口中的方法,但是随便实现了方法的内容】
// 动态的实现接口中的方法
@Test
public void testGenerateAccountDaoImpl() throws Exception{
// 获取类池
ClassPool pool = ClassPool.getDefault();
// 制造类
CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
// 制造接口
CtClass ctInterface = pool.makeInterface("com.powernode.bank.dao.AccountDao");
// 实现接口[只有类实现了接口,最后才能强转Wie接口的类型]
ctClass.addInterface(ctInterface);
// 获取接口中所有的方法
Method[] methods = AccountDao.class.getDeclaredMethods();
// 流式遍历
Arrays.stream(methods).forEach(method -> {
// method 是接口中的抽象方法,我们现在要实现这些方法
try {
// 创建我们要拼接的方法
StringBuilder methodCode = new StringBuilder();
// 追加修饰符列表
methodCode.append("public ");
// 追加返回值类型
methodCode.append(method.getReturnType().getName());
// 追加空格
methodCode.append(" ");
// 追加方法名
methodCode.append(method.getName());
// 追加左括号
methodCode.append("(");
// 拼接参数列表:(1)先获得所有返回值类型
Class<?>[] parameterTypes = method.getParameterTypes();
// 遍历数组
for (int i = 0; i < parameterTypes.length; i++) {
// 获取当前参数类型
Class<?> parameterType = parameterTypes[i];
// 拼接当前的参数类型
methodCode.append(parameterType.getName());
// 拼接空格
methodCode.append(" ");
// 拼接参数名
methodCode.append("arg" + i);
// 不是参数列表最后一个元素,都要拼接一个逗号
if(i != parameterTypes.length - 1){
methodCode.append(",");
}
}
//追加一条输出语句
methodCode.append("){System.out.println(1111);");
// 判断当前方法的返回值类型
String returnTypeSimpleName = method.getReturnType().getSimpleName();
// 分情讨论 [我们接口这块只有 void、String、double]
if("void".equals(returnTypeSimpleName)){
// 不返回
}else if("int".equals(returnTypeSimpleName)){
methodCode.append("return 1;");
}else if("String".equals(returnTypeSimpleName)){
methodCode.append("return \"hello\";");
}
// 添加结束右括号
methodCode.append("}");
System.out.println(methodCode);
CtMethod ctMethod = CtMethod.make(methodCode.toString(), ctClass);
ctClass.addMethod(ctMethod);
} catch (Exception e) {
e.printStackTrace();
}
});
// 在内存中生成class,并且添加到JVM中
Class<?> clazz = ctClass.toClass();
// 创建对象
AccountDao accountDao = (AccountDao) clazz.newInstance();
// 调用方法
accountDao.insert("bala");
accountDao.delete();
accountDao.update("bala", 1000.0);
accountDao.selectByActno("bala");
}
修饰符 >> 返回值类型 >> 方法名 >> 参数列表 【此处省略了空格、逗号、参数名】
method.getParameterTypes()
获取所有的参数类型,通过遍历将参数类型和参数拼接进去method.getReturnType().getSimpleName()
获取返回值类型,然后分情况讨论,我们返回的内容也简化了,因为此处只是想说明是一个什么样的原理6、如果运行的时候出现以下的报错:
这是因为高版本的 JDK 使用了base类,我们要通过以下操作来解决这个问题
7、利用Javassist实现在dao层的 AccountDao接口
(1)接口如下:【包含参数和返回值类型】
package com.powernode.bank.dao;
import com.powernode.bank.pojo.Account;
/**
* 账户的Dao对象,负责对 t_act 表进行增删改查
* Dao 中的方法与业务逻辑不存在联系
* @author Bonbons
* @version 1.0
*/
public interface AccountDao {
/**
* 根据账号查询账户信息
* @param actno 账户id
* @return 返回账户的信息
*/
Account selectByActno(String actno);
/**
* 更新账户的信息
* @param act 被更新的账户
* @return 返回更新结果(成功/失败)
*/
int updateActno(Account act);
}
(2)我们通过 GenerateDaoProxy 的 generate 方法实现在内存中根据接口创建实现类
package com.powernode.bank.utils;
import org.apache.ibatis.javassist.ClassPool;
import org.apache.ibatis.javassist.CtClass;
import org.apache.ibatis.javassist.CtMethod;
import org.apache.ibatis.session.SqlSession;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* 可以动态的生成DAO的实现类
* @author Bonbons
* @version 1.0
*/
public class GenerateDaoProxy {
/**
* 生成dao接口的实现类,返回实现类的对象
* @param daoInterface 接口
* @return 返回的对象
*/
public static Object generate(SqlSession sqlSession, Class daoInterface){
// 获取类池
ClassPool pool = ClassPool.getDefault();
// 制造类[类名采用接口名 + Proxy(只要类名和接口名不冲突就行)]
CtClass ctClass = pool.makeClass(daoInterface.getName() + "Proxy");
// 制造接口
CtClass ctInterface = pool.makeInterface(daoInterface.getName());
// 实现接口
ctClass.addInterface(ctInterface);
// 获得接口中的所有方法
Method[] methods = daoInterface.getDeclaredMethods();
// 采用流式遍历
Arrays.stream(methods).forEach(method -> {
try {
// 拼接方法
StringBuilder methodCode = new StringBuilder();
methodCode.append("public ");
methodCode.append(method.getReturnType().getName());
methodCode.append(" ");
methodCode.append(method.getName());
methodCode.append("(");
// 参数列表
Class<?>[] parameterTypes = method.getParameterTypes();
for(int i = 0; i < parameterTypes.length; i++){
Class<?> parameterType = parameterTypes[i];
methodCode.append(parameterType);
methodCode.append(" ");
methodCode.append("arg");
methodCode.append(i);
if(i != parameterTypes.length - 1){
methodCode.append(",");
}
}
methodCode.append("){");
// 内部代码
// 拼接创建会话的语句,但注意要使用全限定类名
methodCode.append("org.apache.ibatis.session.SqlSession sqlSession = com.powernode.bank.utils.SqlSessionUtil.openSession()");
// mybatis 规定了namespace必须为Dao中接口的全限定类名,id必须为接口中的方法名 >> 此处我们就可以获得 sql的Id
String sqlId = daoInterface.getName() + "." + method.getName();
// 获取当前方法的SQL类型[CRUD]
// SqlCommandType sqlCommandType = sqlSession.getConfiguration().getMappedStatement(sqlId).getSqlCommandType();
String sqlCommandType = sqlSession.getConfiguration().getMappedStatement(sqlId).getSqlCommandType().name();
// 分情况讨论
if("UPDATE".equals(sqlCommandType)){
methodCode.append("return sqlSession.update(\""+sqlId+"\", arg0);");
}else if("SELECT".equals(sqlCommandType)){
String returnType = method.getReturnType().getName();
methodCode.append("return ("+returnType+")sqlSession.selectOne(\""+sqlId+"\", arg0);");
}
methodCode.append("}");
// 制造方法
CtMethod ctMethod = CtMethod.make(methodCode.toString(), ctClass);
// 将方法添加到类中
ctClass.addMethod(ctMethod);
} catch (Exception e) {
e.printStackTrace();
}
});
// 创建对象
Object obj = null;
try {
Class<?> clazz = ctClass.toClass();
obj = clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
}
1、对于我们用 Javassist 方式实现的 GenerateDaoProxy 类感觉比直接写dao中接口的实现类费事,那我们为什么还去写这个方法呢?
实际上确实没啥必要去自己写generate方法,因为 mybatis 为我们封装了这个接口,我们直接调用即可。
之所以我们自己去实现是为了容易理解javassist的底层是如何实现的。
2、使用 mybatis 的接口有什么要求吗?
当然,在Mapper 映射文件中 namespace 只能为 接口的全限定类名,而且其中SQL语句的 id 要与接口中的方法名对应上。
3、比较一下我们自己写的静态类方法和 mybatis 提供的接口代理是如何使用的?
//数据库操作的对象[第一种采用接口的实现类]
private AccountDao accountDao= new AccountDaoImpl();
// 使用我们的工具类动态生成
private AccountDao accountDao = (AccountDao) GenerateDaoProxy1.generate(SqlSessionUtil.openSession(), AccountDao.class);
// 使用mybatis提供的接口代理机制
private AccountDao accountDao = SqlSessionUtil.openSession().getMapper(AccountDao.class);
4、为了更好的说明如何使用这个接口代理,我们写一个增删改查的 java 案例
(1)准备数据库的一张表 t_car 【其实之前用过这个表】
(2)在 idea 中创建一个新的普通Maven Java模块 mybatis-005-crud2
(3)两个 xml 文件如下
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/powernode"/>
<property name="username" value="root"/>
<property name="password" value="111111"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--sql映射文件创建好之后,需要将该文件路径配置到这里-->
<mapper resource="CarMapper.xml"/>
</mappers>
</configuration>
<?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="com.powernode.mybatis.mapper.CarMapper">
<insert id="insert">
-- 因为id在设计表的时候我们采用了自增的方式,所以插入数据的时候不用指定id
insert into t_car values (null, #{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
</insert>
<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>
<delete id="deleteById">
delete from t_car where id = #{id}
</delete>
<select id="selectById" resultType="com.powernode.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="com.powernode.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>
(4)贴一下我们封装的汽车的普通 Java 类 【之所以说普通因为只有属性、构造方法、get和set、toString方法】
package com.powernode.mybatis.pojo;
/**
* @author Bonbons
* @version 1.0
*/
public class Car {
// id,car_num,brand,guide_price,produce_time,car_type
// 使用包装类,出现null时不会报错
// 对于这些私有属性要与表中数据对应上
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;
}
//提供get和set方法
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;
}
//重写toString方法
@Override
public String toString() {
return "Car{" +
"id=" + id +
", carNum='" + carNum + '\'' +
", brand='" + brand + '\'' +
", guidePrice=" + guidePrice +
", produceTime='" + produceTime + '\'' +
", carType='" + carType + '\'' +
'}';
}
}
(5)定义的工具类 SqlSessionUtil【用于创建连接对象,因为此处没啥业务,我们就不用ThreadLocal了】
package com.powernode.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;
/**
* @author Bonbons
* @version 1.0
*/
public class SqlSessionUtil {
private SqlSessionUtil(){}
//定义一个SqlSession
private static final SqlSessionFactory sqlSessionFactory;
//在类加载的时候初始化SqlSessionFactory
static {
try {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
//定义一个全局的ThreadLocal,可以保证一个SqlSession对应一个线程
private static ThreadLocal<SqlSession> local = new ThreadLocal<>();
//通过一个公有的方法为外部提供会话的对象 >> 确保同一个线程操作的是同一个连接对象
public static SqlSession openSession(){
//我们用local去获取会话
SqlSession sqlSession = local.get();
//如果当前没有开启的会话就去创建一个,如果get到了就用这个[确保我们操作的是同一个连接对象]
if(sqlSession == null){
sqlSession = sqlSessionFactory.openSession();
//将SqlSession对象绑定到当前线程上
local.set(sqlSession);
}
return sqlSession;
}
/**
* 关闭SqlSession对象并从当前线程中解绑
* @param sqlSession 会话对象
*/
public static void close(SqlSession sqlSession){
if(sqlSession != null){
sqlSession.close();
local.remove();
}
}
}
(6)我们定义对数据库中表操作的接口 【习惯问题,正常都叫XxxDao,使用mybatis的dao层都叫mapper层】
package com.powernode.mybatis.mapper;
import com.powernode.mybatis.pojo.Car;
import java.util.List;
/**
* @author Bonbons
* @version 1.0
*/
public interface CarMapper {
/**
* 新增车辆信息
* @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();
}
(7)最后就可以在test包下写我们的测试方法了
package com.powernode.mybatis.test;
import com.powernode.mybatis.mapper.CarMapper;
import com.powernode.mybatis.pojo.Car;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
/**
* @author Bonbons
* @version 1.0
*/
public class CarMapperTest {
@Test
public void testInsert(){
// 创建连接对象
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
// 创建我们要添加的Car
Car car = new Car(null, "1","卡罗拉", 100.0, "2022-11-04", "燃油车");
// 调用我们的insert方法
int count = mapper.insert(car);
System.out.println(count);
sqlSession.commit();
sqlSession.close();
}
@Test
public void testDeleteById(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
int count = mapper.deleteById(1L);
sqlSession.commit();
sqlSession.close();
System.out.println(count);
}
@Test
public void testUpdate(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Car car = new Car(21L, "21","卡罗拉新款", 50.0, "2022-11-04", "燃油车");
mapper.update(car);
sqlSession.commit();
sqlSession.close();
}
@Test
public void testSelectById(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Car car = mapper.selectById(2L);
System.out.println(car);
sqlSession.close();
}
@Test
public void testSelectAll(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
List<Car> cars = mapper.selectAll();
cars.forEach(car -> System.out.println(car));
}
}
(8)所有的方法测试都是通过的,最后再赘述一下流程
利用工具类创建会话 >> 调用getMapper方法(参数为 CarMapper.class) >> 利用mapper调用我们的方法