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();}