目录
一:MyBatis使用⼩技巧
1. #{}和${}
2. typeAliases
3. mappers
4. IDEA配置⽂件模板
5. 插⼊数据时获取⾃动⽣成的主键
一:MyBatis使用⼩技巧
1. #{}和${}
#{}:先编译sql语句,再给占位符传值,底层是PreparedStatement实现。可以防⽌sql注⼊,⽐较常⽤。
${}:先进⾏sql语句拼接,然后再编译sql语句,底层是Statement实现。存在sql注⼊现象。只有在需要进⾏sql语句关键字拼接的情况下才会⽤到。
(1)定义接口CarMapper ,面向接口编程
package com.bjpowernode.mybatis.mapper;
import com.bjpowernode.mybatis.pojo.Car;
import java.util.*;
public interface CarMapper {
// 根据汽车类型查询
List<Car> selectByCarType(String carType);
}
(2)在CarMapper.xml文件中编写sql语句
注意:namespace是接口CarMapper的完整类名,id是接口对应的方法名
<?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.bjpowernode.mybatis.mapper.CarMapper">
<select id="selectByCarType" resultType="com.bjpowernode.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 car_type = #{carType}
</select>
</mapper>
(3)编写测试类,看执行结果对比
package com.bjpowernode.mybatis.test;
import com.bjpowernode.mybatis.mapper.CarMapper;
import com.bjpowernode.mybatis.pojo.Car;
import com.bjpowernode.mybatis.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class CarMapperTest {
@Test
public void testSelectByCarType(){
SqlSession sqlSession = SqlSessionUtils.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
List<Car> cars = mapper.selectByCarType("燃油车");
for (Car car :cars){
// 会调toString方法
System.out.println(car);
}
sqlSession.close();
}
}
①使用#{}执行结果,能正常执行结果
特点:先执行SQL语句的编译,然后给SQL语句的占位符问号?传值
②使用${}执行结果,会抛出异常,直接拼接字符串但是没有引号
特点:先执行SQL语句的拼接,然后再对SQL语句进行编译
(4)#{}和${}的选择
注:如果需要SQL语句的关键字放到SQL语句中,只能使用${},因为#{}是以值的形式放到SQL语句当中;例如:升序或者降序排需要传asc或者desc,此时要把这个关键字传进去,就需要${}
①接口类中的方法
package com.bjpowernode.mybatis.mapper;
import com.bjpowernode.mybatis.pojo.Car;
import java.util.*;
public interface CarMapper {
// 根据汽车类型查询
List<Car> selectByCarType(String carType);
// 查询所有的汽车信息,然后通过asc升序,desc降序
List<Car> selectByAscOrDesc(String ascOrDesc);
}
②编写sql语句,根据传参按照produce_time升序或者降序
<?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.bjpowernode.mybatis.mapper.CarMapper">
<select id="selectByCarType" resultType="com.bjpowernode.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 car_type = #{carType}
</select>
<select id="selectByAscOrDesc" resultType="com.bjpowernode.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
order by
produce_time #{ascOrDesc}
</select>
</mapper>
③编写测试程序
package com.bjpowernode.mybatis.test;
import com.bjpowernode.mybatis.mapper.CarMapper;
import com.bjpowernode.mybatis.pojo.Car;
import com.bjpowernode.mybatis.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class CarMapperTest {
@Test
public void selectByAscOrDesc(){
SqlSession sqlSession = SqlSessionUtils.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
List<Car> cars = mapper.selectByAscOrDesc("asc");
for (Car car :cars){
// 会调toString方法
System.out.println(car);
}
sqlSession.close();
}
}
使用#{},先编译在传值,传的是一个字符串,会有引号,明显不符合语法!
使用${},先把关键字拼串上去,在进行编译,符合语法规则!
(5) 使用${}完成表名拼接
注:这里需要查询新的表名,所以需要编写新的PoJo类Log、新建配置文件LogMapper.xml、新建一个接口LogInterface、新建测试类LogMapperTest类进行测试、在核心配置文件mybatis-config.xml当中引入LogMapper.xml
①现实业务当中,可能会存在分表存储数据的情况,因为一张表存储数据的话,数据量太大,查询效率比较低。
②可以将这些数据有规律的分表存储,这样扫描的数据量变少了,在查询的时候效率就比较高。例如日志表:专门存储日志信息的,可以每天生成一个新表,每张表以当天日期作为名称,例如:t_log_20220901、t_log_20220902....
③假如想知道某一天的日志信息,假设今天是20230103,那么直接把日期传进去,完成“t_log_日期表”的拼接。
<?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.LogMapper">
<select id="selectAllByTable" resultType="com.bjpowernode.mybatis.pojo.Log">
<!--select * from t_log_#{date}-->
select * from t_log_${date}
</select>
</mapper>
(6)使用${}完成批量删除
注:批量删除对应的sql语句有两种写法
第一种:使用or的形式,delete from t_user where id = 1 or id = 2 or id = 3;
第二种:使用in的形式,delete from t_user where id in(1, 2, 3);
①定义的方法中参数实际上是一个String类型的字符串,我们传参的时候,也是一个字符串传过去,例如:mapper.deleteBatch("1,2,3")的形式。
②关键是我们先拼串再编译,还是先编译在传值;前者是字符串的完美拼接,后者是直接把一个字符串传过去,会带有引号!
<delete id="deleteBatch">
delete from t_car where id in(${ids})
</delete>
(7)使用${}完成模糊查询
需求:根据汽车品牌进行模糊查询
例如:select * from t_car where brand like '%奔驰%';
<select id="selectByBrandLike" resultType="CAR">
select
id,
car_num as carNum,
brand,
guide_price as guidePrice,
produce_time as produceTime,
car_type as carType
from
t_car
where
<!--brand like '%#{brand}%'-->
brand like '%${brand}%'
brand like concat('%',#{brand},'%')
brand like concat('%','${brand}','%')
brand like "%"#{brand}"%"
</select>
①如果使用"%#{brand}%",最终#{}底层肯定是转化为?,但是比较尴尬的是放到双引号或者单引号"?"的?是无法识别的,所以无法进行传值!
②解决方法1:使用"%${brand}%",会先进行拼串,然后在编译!
③解决方法2:concat函数,这个是mysql数据库当中的一个函数,专门进行字符串拼接,concat('%',#{brand},'%');这里也可以使用${band},外面加一个单引号,比较鸡肋,
concat('%','${brand}','%')。④解决方法3:"%"#{brand}"%",把两个%用引号括起来,就能识别中间的?了,就能正常传值了。
2. typeAliases
使用 typeAliases标签完成别名机制!
(1)我们打开CarMapper.xml文件,发现resultType标签的全限定名称很长,包括我们以后写其它类型的查询语句,都要写这个带包的类名;所以就使用别名机制先定义别名。
<select id="selectByCarLike" resultType="com.bjpowernode.mybatis.pojo.Car">
</select>
(2)第一种:在核心配置文件mybatis-config.xml文件中使用typeAliases标签下的子标签typeAlias标签起别名。
注:namespace标签必须写全限定名称,是不能起别名的!
①type属性:指定给那个类型起别名
②alias:指定别名
<typeAliases>
<typeAlias type="com.bjpowernode.mybatis.pojo.Car" alias="car" />
</typeAliases>
③ 这样就能在CarMapper.xml文件中运用别名了,并且不区分大小写!
<select id="selectByCarLike" resultType="car">
</select>
④实际上alias属性是可以省略的,有默认的别名,别名是类的简名;例如:com.bjpowernode.mybatis.pojo.Car对应的就是Car、car、cAr等等,不区分大小写。
(3)第二种:在核心配置文件mybatis-config.xml文件中使用typeAliases标签下的子标签package指定包名即可。(常用)
我们使用package标签指定一个包名,那么这个包下所有的类全部自动起别名,别名就是类简名,不区分大小写
<typeAliases>
<package name="com.bjpowernode.mybatis.pojo" />
</typeAliases>
(4)小总结
所有别名不区分大小写;namespace不能使用别名机制!
<typeAliases>
<!--别名自己指定的-->
<typeAlias type="com.powernode.mybatis.pojo.Car" alias="aaa"/>
<typeAlias type="com.powernode.mybatis.pojo.Log" alias="bbb"/>
<!--采用默认的别名机制-->
<typeAlias type="com.powernode.mybatis.pojo.Car"/>
<typeAlias type="com.powernode.mybatis.pojo.Log"/>
<!--包下所有的类自动起别名。使用简名作为别名。-->
<package name="com.powernode.mybatis.pojo"/>
</typeAliases>
3. mappers
(1)mapper标签的属性可以有三个:
①resource:这种方式是从类的根路径下开始查找资源;采用这种方式,配置文件需要放到类路径当中才行。
②url:这种方式是一种绝对路径的方式,这种方式不要求配置文件必须放到类路径当中,哪里都行,只要提供一个绝对路径就行;这种方式使用极少,因为移植性太差。
③class:这个位置提供的是mapper接口的全限定接口名,必须带有包名的。
例如:<mapper class="com.powernode.mybatis.mapper.CarMapper"/>,class指定的是:com.powernode.mybatis.mapper.CarMapper,那么mybatis框架会自动去com/powernode/mybatis/mapper目录下查找CarMapper.xml文件。
注意:也就是说,如果采用这种方式,必须保证CarMapper.xml文件和CarMapper接口必须在同一个目录下,并且名字一致。如:CarMapper接口-> CarMapper.xml。
解释:所谓的同一个目录,是在resource目录下创建包名,并且这个包名与java下的CarMapper接口包名必须一致,然后把配置文件CarMapper.xml扔到包名里;实际上java和resource都是根目录,只不过两种展现形式!
解释:在resource下创建包,实际上是创建目录,因为只有在java下创建包才是"点"的形式,例如:com.bjpowernode就表示com目录下的bjpowernode目录;对于resource下创建包就是直接创建目录,例如:com/bjpowernode也表示com目录下的bjpowernode目录,如果采用com.bjpowernode就表示一个名为com.bjpowernode的目录。
<mappers>
<mapper resource="CarMapper.xml"/> 要求类的根路径下必须有:CarMapper.xml
<mapper url="file:///d:/CarMapper.xml"/> 要求在d:/下有CarMapper.xml文件
<mapper class="com.powernode.mybatis.mapper.CarMapper"/> 全限定接口名,带有包名
</mappers>
(2)假如有很多个接口名,要写很多个全限定接口名也很麻烦;实际上在mappers标签下还有一个package属性,用来指定包名,这种方式在开发中是比较常用的。
前提:XML文件必须和接口放在一起,并且名字一致!
解释:指定报名,实际上就是指定这个路径,在这个路径下查找配置文件。
<mappers>
<package name="com.bjpowernode.mybatis.mapper" />
</mappers>
4. IDEA配置⽂件模板
mybatis-config.xml和SqlMapper.xml⽂件可以在IDEA中提前创建好模板,以后通过模板创建配置⽂件
(1)准备好的mybatis-config.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>
<properties resource=""/>
<typeAliases>
<package name=""/>
</typeAliases>
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name=""/>
</mappers>
</configuration>
(2)准备好的SqlMapper.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">
<mapper namespace="">
</mapper>
(3)步骤:File--->Settings--->Editor--->File and Code Templates
(4)使用:以后直接alt+insert就能找到这个模板
(5)选定这个模板后,就会让你输出文件的名字,例如:mybatis-config
(6)点击ok,就会自动生成我们自定义模板的核心配置文件mybatis-config.xml
5. 插⼊数据时获取⾃动⽣成的主键
(1)前面用的主键一直是自动生成的,所以我们并不知道主键是多少,要是下面这种业务,⼀个⽤户有多个⻆⾊,一对多,两张表,多的表加外键
(2)插⼊⼀条新的记录之后,⾃动⽣成了主键,⽽这个主键需要在其他表中使⽤时;插⼊⼀个⽤户数据的同时需要给该⽤户分配⻆⾊:需要将⽣成的⽤户的id插⼊到⻆⾊表的user_id字段 上。
①第⼀种⽅式:可以先插⼊⽤户数据,再写⼀条查询语句获取id,然后再插⼊user_id字段。【⽐较麻烦】
②第⼆种⽅式:mybatis提供了⼀种⽅式更加便捷。
(3)主要是在插入数据时,使用两个属性
①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>
(4)测试结果
①如果不加上这两个参数,打印结果主键显示null
②如果加上这两个参数,打印结果就会显示自动生成的主键