小黑子—MyBatis:第三章

news/2025/1/30 8:36:20/

MyBatis入门3.0

  • 七 小黑子使用javassist生成类
    • 7.1 Javassist的使用
    • 7.2 javassist生成动态类并实现接口
    • 7.3 工具类GenerateDaoProxy的编写
      • 7.3.1 每一个方法体的动态拼接
      • 7.3.2 MyBatis的getMapper方法
  • 八 MyBatis中接口代理机制及使用
    • 8.1 面向接口的方式进行CRUD
      • 8.1.1 步骤1
      • 8.1.2 步骤2
  • 九 小黑子的MyBatis小技巧
    • 9.1 #{} 和 $()
    • 9.2 拼接表名
    • 9.3 批量删除
    • 9.4 模糊查询
    • 9.5 别名标签 typeAliases
    • 9.6 mapper的配置
    • 9.7 IDEA配置模板文件
    • 9.8 插入数据时获取自动生成的主键

七 小黑子使用javassist生成类

javassist是一个开源的分析、编辑和创建java字节码类库。是由东京工业大学的数学和计算机科学系的Shigeru Chiba(千叶滋)所创建的。它已加入了开发源代码JBoss应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态"AOP"框架

7.1 Javassist的使用

  • 我们要使用javassist,首先要引入它的依赖
<dependency><groupId>org.javassist</groupId><artifactId>javassist</artifactId><version>3.29.1-GA</version>
</dependency>
  • 样例代码:
package com.powernode.javassist;import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import org.junit.Test;import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class JavassistTest {@Testpublic void testGenerateFirstClass() throws CannotCompileException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {//获取类池,这个类池就是用来给我生成class的ClassPool pool = ClassPool.getDefault();//创造类(需要告诉javassist,类名是啥)CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDapImpl");// 创造方法String methodCode = "public void insert(){System.out.println(123);}";CtMethod ctMethod = CtMethod.make(methodCode, ctClass);//将方法添加到类中ctClass.addMethod(ctMethod);//在内存中生成classctClass.toClass();//类加载到JVM当中,返回AccountDaoImplClass<?> clazz = Class.forName("com.powernode.bank.dao.impl.AccountDapImpl");//创建对象Object obj = clazz.newInstance();//获取AccountDaoImpl中的insert方法Method insertMethod = clazz.getDeclaredMethod("insert");//调用方法insertinsertMethod.invoke(obj);}
}

在这里插入图片描述

运行要注意:在配置中加两个参数,要不然会有异常。

  • –add-opens java.base/java.lang=ALL-UNNAMED
  • –add-opens java.base/sun.net.util=ALL-UNNAMED
    在这里插入图片描述
    在这里插入图片描述

7.2 javassist生成动态类并实现接口

在这里插入图片描述

package com.powernode.javassist;import com.powernode.bank.dao.AccountDao;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import org.junit.Test;public class JavassistTest {@Testpublic void testGenerateImpl() throws Exception {//获取类池ClassPool pool = ClassPool.getDefault();//制作类CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDapImpl");//制造接口CtClass ctInterface = pool.makeInterface("com.powernode.bank.dao.AccountDao");//添加接口到类中ctClass.addInterface(ctInterface);// 实现接口中的方法//制造方法CtMethod ctMethod = CtMethod.make("public void delete(){System.out.println(\"hello delete\");}", ctClass);//将方法添加到类中ctClass.addMethod(ctMethod);//在内存中生成类,同时将生成的类加载到JVM当中Class<?> clazz = ctClass.toClass();AccountDao accountDao = (AccountDao) clazz.newInstance();accountDao.delete();}
}

在这里插入图片描述

  • 实现接口中的所有方法
 @Testpublic void testGenerateAccountDaoImpl() throws Exception{// 获取类池ClassPool pool = ClassPool.getDefault();//制造类CtClass ctClass = pool.makeInterface("com.powernode.bank.dao.impl.AccountDapImpl");//制造接口CtClass ctInterface = pool.makeInterface("com.powernode.bank.dao.AccountDao");//实现接口ctClass.addInterface(ctInterface);//实现接口中所有的方法//获取接口中所有的方法Method[] methods  = AccountDao.class.getDeclaredMethods();Arrays.stream(methods).forEach(method -> {//method 是接口中的抽象方法try {// public void delete(){System.out.println(111);}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<?> parameter =  parameterTypes[i];methodCode.append(parameter.getName());methodCode.append(" ");methodCode.append("arg"+i);if (i != parameterTypes.length-1){methodCode.append(",");}}methodCode.append("){System.out.println(11111);");//添加返回值String returnName = method.getReturnType().getSimpleName();//获取返回值类名的简类名if ("int".equals(returnName)){methodCode.append("return 1;");} else if ("String".equals(returnName)) {methodCode.append("return \"hello\";");}methodCode.append("}");CtMethod ctMethod = CtMethod.make(methodCode.toString(), ctClass);//将方法都加到类中ctClass.addMethod(ctMethod);} catch (CannotCompileException e) {e.printStackTrace();}});//在内存中生成类,同时生成的类加载到JVM当中Class<?> aClass = ctClass.toClass();AccountDao accountDao = (AccountDao)aClass.newInstance();//执行里面的方法accountDao.insert("aaaaa");accountDao.delete();accountDao.update("aaaa",1000.00);accountDao.selectByActno("aaaa");
}

7.3 工具类GenerateDaoProxy的编写

工具类GenerateDaoProxy能够动态地提供接口实现类

mybatis自己内置有javassist,mybatis号称轻量级的,只需要一个jar包就行

package com.powernode.bank.utils;import org.apache.ibatis.javassist.ClassPool;
import org.apache.ibatis.javassist.CtClass;
import org.apache.ibatis.javassist.CtMethod;import java.lang.reflect.Method;
import java.util.Arrays;/*** 工具类:可以动态地生成DAO的实现类(或者说可以动态生成DAO的代理类)* @author 小黑子* @version 1.0
*/
public class GenerateDaoProxy {/*** 生成dao接口实现类,并且将实现类的对象创建出来并返回* @param daoInterface dao接口* @version 1.0*/public static Object generate(Class daoInterface){//类池ClassPool pool = ClassPool.getDefault();//制造类(com.powernode.bank.dao.AccountDao->com.powernode.bank.dao.impl.AccountDapImpl)final CtClass ctClass = pool.makeClass(daoInterface.getName()+"Proxy");//制造接口CtClass ctInterface = pool.makeInterface(daoInterface.getName());//实现接口中的所有方法Method[] methods = daoInterface.getDeclaredMethods();Arrays.stream(methods).forEach(method->{//method是抽象方法//将method这个抽象方法进行实现try {//public Account selectByActno(String arg0,int arg1,int arg2){代码;}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.getName());methodCode.append(" ");methodCode.append("arg"+i);if(i!=parameterTypes.length-1){methodCode.append(",");}}methodCode.append(")");methodCode.append("{");//需要方法体的代码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 null;}
}

7.3.1 每一个方法体的动态拼接

AccountDaoImpl的mybatis规范

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;public class AccountDaoImpl implements AccountDao {@Overridepublic Account selectByActno(String arg0) {SqlSession sqlSession = SqlSessionUtil.openSession();
//        Account account = (Account) sqlSession.selectOne("account.selectByActno",actno);
//        return account;return (Account) sqlSession.selectOne("account.selectByActno",arg0);}@Overridepublic int updateByActno(Account arg0) {SqlSession sqlSession = SqlSessionUtil.openSession();
//        int count = sqlSession.update("account.updateActno", act);
//        return count;return sqlSession.update("account.updateActno", arg0);}
  • 动态拼接
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.mapping.SqlCommandType;
import org.apache.ibatis.session.SqlSession;import java.lang.reflect.Method;
import java.util.Arrays;/*** 工具类:可以动态地生成DAO的实现类(或者说可以动态生成DAO的代理类)* @author 小黑子* @version 1.0
*/
public class GenerateDaoProxy {/*** 生成dao接口实现类,并且将实现类的对象创建出来并返回* @param daoInterface dao接口* @version 1.0*/public static Object generate(SqlSession sqlSession, Class daoInterface){//类池ClassPool pool = ClassPool.getDefault();//制造类(com.powernode.bank.dao.AccountDao->com.powernode.bank.dao.impl.AccountDapImpl)final 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->{//method是抽象方法//将method这个抽象方法进行实现try {//public Account selectByActno(String arg0,int arg1,int arg2){代码;}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.getName());methodCode.append(" ");methodCode.append("arg"+i);if(i!=parameterTypes.length-1){methodCode.append(",");}}methodCode.append(")");methodCode.append("{");//需要方法体的代码methodCode.append("org.apache.ibatis.session.SqlSession  sqlSession = com.powernode.bank.utils.SqlSessionUtil.openSession();");methodCode.append("sqlSession");//需要知道是什么类型的sql语句// sql语句的id是框架使用者提供的,具有多边性。对于我框架的开发人员来说。我不知道//既然我框架开发者不知道sqlId。怎么办?mybatsi框架的开发者于是就出台了一个规定:凡是使用GenerateDaoProxy机制的//sqlId都不能随便写。namespace必须是dao接口的全限定名称,id必须是dao接口中的方法名String sqlId = daoInterface.getName() + "," + method.getName();SqlCommandType sqlCommandType = sqlSession.getConfiguration().getMappedStatement(sqlId).getSqlCommandType();if(sqlCommandType == sqlCommandType.INSERT){}if(sqlCommandType == sqlCommandType.DELETE){}if(sqlCommandType == sqlCommandType.UPDATE){methodCode.append(" return sqlSession.update(\""+sqlId+"\", arg0)");}if(sqlCommandType == sqlCommandType.SELECT){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;}
}

7.3.2 MyBatis的getMapper方法

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--sqlMapper.xml文件的编写者,提供者是谁?使用你mybatis框架的java程序员负责提供的-->
<!--要想使用这种机制:namespace必须是dao接口的全限定名-->
<mapper namespace="account">
<!--    要使用这种机制,id必须是dao接口的方法名--><select id="selectByActno" resultType="com.powernode.bank.pojo.Account">select * from t_act where actno = #{actno}</select><update id="updateByActno">update t_act set balance = #{balance} where actno = #{actno}</update>
</mapper>

在mybatis当中。mybatis提供了相关的机制,也可以为动态为我们生成接口的实现类。(代理类:接口的代理)

mybatis当中实际上采用了代理模式,在内存中生成dao接口的代理类,然后创建代理类的实例

使用mybatis的这种代理机制的前提:

  • SqlMapper.xml文件中namespace必须是dao接口的全限定名称,id必须是dao接口中的方法名

怎么写?
AccountDao accountDao = SqlSessionUtil.openSession().getMapper(AccountDao.class);

八 MyBatis中接口代理机制及使用

其实以上所讲内容mybatis内部已经实现了。直接调用以下代码即可获取dao接口的代理类:

AccountDao accountDao = (AccountDao)sqlSession.getMapper(AccountDao.class);

使用以上代码的前提是:AccountMapper.xml文件中的namespace必须和dao接口的全限定名称一致,id必须和dao接口中方法名一致

8.1 面向接口的方式进行CRUD

8.1.1 步骤1

在这里插入图片描述
CarMapper接口:

package com.powernode.mybatis.mapper;import com.powernode.mybatis.pojo.Car;import java.util.List;public interface CarMapper {/*** @description: 新增car* @return*/int insert(Car car);/*** @description: 根据id删除car* @return*/int deleteById(Long id);/*** @description: 根据id修改汽车信息* @return*/int update(Car car);/*** @description: 获取单个的汽车信息* @return*/Car selectById(Long id);/*** @description: 获取所有的汽车信息* @return*/List<Car> selectAll();
}

资源下的CarMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace先随意写一个-->
<mapper namespace="com.powernode.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 setcar_num = #{carNum},brand = #{brand}, guide_price = #{guidePrice},produce_time = #{produceTime},car_type = #{carType}where id = #{id}</update><select id="selectById" resultType="com.powernode.mybatis.pojo.Car">selectid,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carTypefrom t_car where id = #{id}</select><select id="selectAll" resultType="com.powernode.mybatis.pojo.Car">selectid,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carTypefrom t_car</select></mapper>

8.1.2 步骤2

测试代码:

package com.powernode.mybatis;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;public class CarMapperTest {@Testpublic void testInsert(){SqlSession sqlSession = SqlSessionUtil.openSession();//面向接口获取接口的代理对象CarMapper mapper = sqlSession.getMapper(CarMapper.class);Car car = new Car(null, "8654", "麻瓜", 3.0, "2022-1-20", "新能源");int insert = mapper.insert(car);System.out.println(insert);sqlSession.commit();sqlSession.close();}@Testpublic void testDeleteById(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);int insert = mapper.deleteById(16L);System.out.println(insert);sqlSession.commit();sqlSession.close();}@Testpublic void testUpdateById(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);Car car = new Car(15L, "22222", "小老板", 3.0, "2022-10-1", "新能源");mapper.update(car);System.out.println(car);sqlSession.commit();sqlSession.close();}@Testpublic void testSelectById(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);Car car = mapper.selectById(33L);System.out.println(car);}@Testpublic void testSelectAll(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);List<Car> cars = mapper.selectAll();cars.forEach(car -> System.out.println(car));}
}

九 小黑子的MyBatis小技巧

9.1 #{} 和 $()

#{}:底层是PreparedStatement实现,特点:先编译sql语句,再给占位符传值。可以防止sql注入,比较常用。

  • 使用该方法会自动给传入的值添加''

${}:底层是Statement实现,特点:先进行sql语句拼接,然后再编译sql语句。不会给值添加'',所以存在sql注入现象。只有在需要进行sql语句关键字拼接的情况下才会用到。

  • 比如在书写升降序查询功能的SQL时,就需要使用${}来时asc或desc不带''形式拼接到SQL语句中
select id,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carType from t_car order by carNum 'asc'

asc是一个升序关键字,不能带单引号的,所以在进行sql语句关键字拼接的时候,必须使用${}

案例:

  • CarMapper接口
package com.powernode.mybatis.mapper;import com.powernode.mybatis.pojo.Car;import java.util.List;public interface CarMapper {/*** @description: 根据汽车类获取汽车信息并且根据desc降序、asc升序* @param asc* @version 1.0*/List<Car> selectAllAscOrDesc(String asc);/*** @description: 根据汽车类获取汽车信息* @param carType* @version 1.0*/List<Car> selectBycarType(String carType);
}
  • CarMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.powernode.mybatis.mapper.CarMapper"><select id="selectAllAscOrDesc" resultType="com.powernode.mybatis.pojo.Car">select id,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carTypefromt_carorder byproduce_time ${ascOrDesc}</select><select id="selectBycarType" resultType="com.powernode.mybatis.pojo.Car">select id,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carTypefrom t_carwherecar_type = #{carType}</select></mapper>
  • 测试包:
    @Testpublic void testSelectAllAscOrDesc(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);List<Car> cars = mapper.selectAllAscOrDesc("asc");cars.forEach(car-> System.out.println(car));sqlSession.commit();sqlSession.close();}

使用#{}来进行升降序查询:
在这里插入图片描述
使用${}来进行升降序查询:
在这里插入图片描述

  • 所以如果是SQL语句的关键字放到SQL语句中,只能使用${},因为#{}是以值的形式放到SQL语句当中的

9.2 拼接表名

向SQL语句当中拼接表名,就需要使用${}

  • 现实业务当中,可能会存在分表存储数据的情况。因为一张表的花,数据量太大,查询效率比较低
  • 可以将这些数据有规律的分表存储,这样在查询的时候效率就比较高。因为扫描的数据量变少了。
  • 日志表:专门储存日志信息的。如果t_log只有一张表 ,这张表中每一天都会产生很多log,慢慢的,这个表中数据会很多

怎么解决问题?

  • 可以每天生成一个新表,每张以当天日期作为名称,例如:

    • t_log_20220901
    • t_log_20220902…
  • 如果想知道某一天的日志信息怎么办?

    • 假设 今天是20220901,那么直接查:t_log_2022901的表即可。

例子:

  • LogMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace先随意写一个-->
<mapper namespace="com.powernode.mybatis.mapper.LogMapper"><select id="selectAllByTable" resultType="com.powernode.mybatis.pojo.Log">select * from t_log_${date}</select>
</mapper>
  • LogMapper
package com.powernode.mybatis.mapper;import com.powernode.mybatis.pojo.Log;import java.util.List;public interface LogMapper {/** @description: 根据日期查询获取表中不同的日志* @version 1.0*/List<Log> selectAllByTable(String date);
}
  • LogMapperTest
package com.powernod.mybatis.test;import com.powernode.mybatis.mapper.LogMapper;
import com.powernode.mybatis.pojo.Log;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;import java.util.List;public class LogMapperTest {@Testpublic void testSelectAllByTable(){SqlSession sqlSession = SqlSessionUtil.openSession();LogMapper mapper = sqlSession.getMapper(LogMapper.class);List<Log> logs = mapper.selectAllByTable("20220901");logs.forEach(log -> System.out.println(log));sqlSession.commit();sqlSession.close();}
}

在这里插入图片描述

在这里插入图片描述

9.3 批量删除

批量删除:一次删除多条记录

  • 批量删除的SQL语句有两种写法:
    • 第一种or:delete from t_car where id=1 or id=2 or id=3;
    • 第二种int:delete from t_car where id in(1,2,3);

案例:

  • CarMapper接口
package com.powernode.mybatis.mapper;import com.powernode.mybatis.pojo.Car;import java.util.List;public interface CarMapper {/** @description: 批量删除* @param ids* @version 1.0*/int deleteBatch(String ids);/*** @description: 根据汽车类获取汽车信息并且根据desc降序、asc升序* @param asc* @version 1.0*/List<Car> selectAllAscOrDesc(String asc);/*** @description: 根据汽车类获取汽车信息* @param carType* @version 1.0*/List<Car> selectBycarType(String carType);
}
  • CarMapper.xml
    <delete id="deleteBatch">delete from t_car where id in (${ids})</delete>
  • 测试
  @Testpublic void testDeleteBatch(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);int count = mapper.deleteBatch("33");System.out.println(count);sqlSession.commit();sqlSession.close();}

在这里插入图片描述

9.4 模糊查询

需求: 根据汽车品牌进行模糊查询

  • CarMapper接口:
public interface CarMapper {/** @description: 根据汽车品牌进行模糊查询* @param brand* @version 1.0*/List<Car> selectByBrandLike(String brand);/** @description: 批量删除* @param ids* @version 1.0*/int deleteBatch(String ids);/*** @description: 根据汽车类获取汽车信息并且根据desc降序、asc升序* @param asc* @version 1.0*/List<Car> selectAllAscOrDesc(String asc);/*** @description: 根据汽车类获取汽车信息* @param carType* @version 1.0*/List<Car> selectBycarType(String carType);
}
  • 测试包
  @Testpublic void testSelectByBrandLike(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);List<Car> cars = mapper.selectByBrandLike("宝马");cars.forEach(car-> System.out.println(car));sqlSession.commit();sqlSession.close();}
  • CarMapper.xml
    • 第一种方案:'%{brand}%'
    • 第二种方案:concat函数,这个是mysql数据库当中的一个函数,专门进行字符串拼接
      concat('%',#{brand},'%')
    • 第三种方案: concat('%',${brand},'%') 比较鸡肋,可以不用
    • 第四种方案:"%"#{brand}"%"
  <select id="selectByBrandLike" resultType="com.powernode.mybatis.pojo.Car">select id,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carTypefromt_carwherebrand like '%${brand}%'</select>

在这里插入图片描述
在这里插入图片描述

9.5 别名标签 typeAliases

第一种方式:typeAlias(可自定义,也可采用默认别名)
在mybatis.xml核心配置文件下写:

    <typeAliases><typeAlias type="com.powernode.mybatis.pojo.Car" alias="aaa"></typeAlias></typeAliases>

首先要注意typeAliases标签的放置位置,如果不清楚的话,可以看看错误提示信息。

typeAliases标签中的typeAlias可以写多个。

  • typeAlias:
    • type属性:指定给哪个类起别名
    • alias属性:别名。
  • alias属性不是必须的,如果缺省的话,type属性指定的类型名的简类名作为别名。比如:com.powernode.mybatis.pojo.Car,简化成:car
  • alias是大小写不敏感的。也就是说假设alias=“aaa”,再用的时候,可以aaa,也可以Aaa,也可以AAa,都行。但是就是不能写漏,或者写多

注意:namespace不能使用别名机制,必须写全限定接口名称、带有包名的
在这里插入图片描述

第二种方式:package(包下所有的类自动起别名,使用简名作为别名)

如果一个包下的类太多,每个类都要起别名,会导致typeAlias标签配置较多,所以mybatis用提供package的配置方式,只需要指定包名,该包下的所有类都自动起别名,别名就是简类名。并且别名不区分大小写。

    <typeAliases><package name="com.powernode.mybatis.pojo"/></typeAliases>

9.6 mapper的配置

SQL映射文件的配置方式包括四种:

  • resource:从类路径中加载
  • url:从指定的全限定资源路径中加载
  • class:使用映射器接口实现类的完全限定类名
  • package:将包内的映射器接口实现全部注册为映射器

resource

这种方式是从类路径中加载配置文件,所以这种方式要求SQL映射文件必须放在resources目录下或其子目录下。

<mappers><mapper resource="org/mybatis/builder/AuthorMapper.xml"/><mapper resource="org/mybatis/builder/BlogMapper.xml"/><mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>

url
这种方式显然使用了绝对路径的方式,这种配置对SQL映射文件存放的位置没有要求,随意。这种方式使用极少,因为移植性太差。

<mappers><mapper url="file:///var/mappers/AuthorMapper.xml"/><mapper url="file:///var/mappers/BlogMapper.xml"/><mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>

class
这个位置提供的是mapper接口的全限定接口名,必须带有包名的。

思考:mapper标签的作用是指定SqlMapper.xml文件的路径,指定接口名有什么作用呢?

  • <mapper class="com.powernode.mybatis.mappper.CarMapper"/>
  • 如果你class指定是:com.powernode.mybatis.mappper.CarMapper
  • 那么mybatis框架会自动去com/powernode/mybatis/mapper目录下查找CarMapper.xml文件

注意:也就是说,如果采用这种方式,那么就必须保证CarMapper.xml文件和CarMapper接口必须在同一个目录下

如果使用这种方式必须满足以下条件:

  • SQL映射文件和mapper接口放在同一个目录下。
  • SQL映射文件的名字也必须和mapper接口名一致。
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers><mapper class="org.mybatis.builder.AuthorMapper"/><mapper class="org.mybatis.builder.BlogMapper"/><mapper class="org.mybatis.builder.PostMapper"/>
</mappers>

将CarMapper.xml文件移动到和mapper接口同一个目录下:

  • 在resources目录下新建:com/powernode/mybatis/mapper【这里千万要注意:不能这样新建 com.powernode.mybatis.dao
  • 将CarMapper.xml文件移动到mapper目录下
  • 修改mybatis-config.xml文件
<mappers><mapper class="com.powernode.mybatis.mapper.CarMapper"/>
</mappers>

package

如果class较多,可以使用这种package的方式,但前提条件和上一种方式一样。

这种包的方式在实际开发中是经常使用的,前提是:xml文件必须和接口放在一起,并且名字一致

<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers><package name="com.powernode.mybatis.mapper"/>
</mappers>

9.7 IDEA配置模板文件

在这里插入图片描述

9.8 插入数据时获取自动生成的主键

前提是:主键是自动生成的。
业务背景:一个用户有多个角色。

在这里插入图片描述

插入一条新的记录之后,自动生成了主键,而这个主键需要在其他表中使用时。
插入一个用户数据的同时需要给该用户分配角色:需要将生成的用户的id插入到角色表的user_id字段上。

第一种方式:可以先插入用户数据,再写一条查询语句获取id,然后再插入user_id字段。【比较麻烦】
第二种方式:mybatis提供了一种方式更加便捷。

  • CarMapper接口
/** @description: 插入Car信息,并且使用生成的主键值* @param car* @version 1.0*/int insertCarUseGeneratedKeys(Car car);
  • CarMapper.xml
<!--useGeneratedKeys="true" 使用自动生成的主键值keyProperty="id" 指定主键值赋值给对象的哪个数学。这个就表示将主键值赋值给Car对象的id属性
--><insert id="insertCarUseGeneratedKeys" useGeneratedKeys="true" keyProperty="id">insert into t_car values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})</insert>
  • 测试
 @Testpublic void testInsertCarUseGenerateKeys(){SqlSession sqlSession = SqlSessionUtil.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);Car car = new Car(null,"9991","凯迪",40.0,"2022-11-11","能源车");mapper.insertCarUseGeneratedKeys(car);System.out.println(car);sqlSession.commit();sqlSession.close();}

在这里插入图片描述
在这里插入图片描述


http://www.ppmy.cn/news/1144008.html

相关文章

【Java项目推荐之黑马头条】自媒体文章实现异步上下架(使用Kafka中间件实现)

自媒体文章上下架功能完成 需求分析 流程说明 接口定义 说明接口路径/api/v1/news/down_or_up请求方式POST参数DTO响应结果ResponseResult DTO Data public class WmNewsDto {private Integer id;/*** 是否上架 0 下架 1 上架*/private Short enable;}ResponseResult 自媒…

【SpringCloud】认识微服务

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 Redis 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 认识微服务 一、 服务架构演变1.1 单体架构…

基于ffmpeg给视频添加时间字幕

FFmpeg是一套可以用来记录、转换数字音频、视频&#xff0c;并能将其转化为流的开源计算机程序&#xff0c;我们可以基于ffmpeg对视频进行各种操作。本文主要介绍基于ffmpeg给视频添加字幕&#xff0c;字幕的内容为视频所播放的时间&#xff08;故需要安装ffmpeg&#xff0c;具…

LeetCode-503-下一个更大元素Ⅱ

题目描述&#xff1a; 给定一个循环数组 nums &#xff08; nums[nums.length - 1] 的下一个元素是 nums[0] &#xff09;&#xff0c;返回 nums 中每个元素的 下一个更大元素 。 数字 x 的 下一个更大的元素 是按数组遍历顺序&#xff0c;这个数字之后的第一个比它更大的数&am…

NAT模式和桥接模式的区别

NAT模式和桥接模式的区别 NAT模式和桥接模式都是虚拟机网络配置的两种方式&#xff0c;主要区别在于虚拟机与外部网络交互的方式不同。 NAT&#xff08;Network Address Translation&#xff0c;网络地址转换&#xff09;模式&#xff1a;在这种模式下&#xff0c;虚拟机和宿主…

PCL 添加自定义数据类型

文章目录 一、简介二、举个栗子三、实现效果参考资料一、简介 PCL带有各种预定义的点类型,从用于XYZ数据的sse对齐结构,到更复杂的n维直方图表示,如PFH(点特征直方图)。这些类型应该足以支持PCL中实现的所有算法和方法。然而,在某些情况下,用户仍然希望定义新的类型。 二、…

Godot 脚本外置参数设置

文章目录 添加脚本设置参数bulid 一下 Godot Engine 4.2 简体中文文档 C# exports 添加脚本 设置参数 Godot 添加脚本后&#xff0c;设置参数。两种形式都可以 [Export]public int Speed { get; set; } 10;[Export]public string Name ;bulid 一下 私有变量也可以

JVM命令行监控工具

JVM命令行监控工具 概述 性能诊断是软件工程师在日常工作中需要经常面对和解决的问题&#xff0c;在用户体验至上的今天&#xff0c;解决好应用的性能问题能带来非常大的收益。 Java作为最流行的编程语言之一&#xff0c;其应用性能诊断一直受到业界广泛关注&#xff0c;可能…