myBatis
- Resources 工具类,这个类在 org.apache.ibatis.io 包中。Resources 类帮助你从类路径下、文件系统或一个 web URL 中加载资源文件。文件在src或者resource文件下,就可以直接写相对路径。
- 获取类路径下文件的方式
- 类加载器:Test1.class.getClassLoader().getResourceAsStream()
- Web里的ServletContext.getRealPath()
- Mybatis框架里的Resources工具类 Resources.getResourceAsStream(“SqlMapConfig.xml”);
MyBatis的Dao层实现的两种方式:
手动对Dao进行实现:传统开发方式
手动实现Dao接口,在方法里创建sqlSession,通过sqlSession的相应方法来实现功能。
代理方式对Dao进行实现:
由mybatis框架通过动态代理的方式,基于Dao接口和SqlMapConfig.xml配置创建代理对象(Dao的实现类,内部有sqlSession方法增强),由代理对象方法来完成Dao操作
**UserMapper userMapper = sqlSession.getMapper(UserMapper.class);**
增删改操作:还是由sqlSession来手动提交事务
若执行完代理对象方法后,表单数据无变动,因为openSession()没有设置为自动提交,或者aop增加事务。
sqlSession.commit();
sqlSession.close();
MyBatis动态sql拼接
where+if
<where>
<if test="id!=0">
and id=#{id}
</if>
<if test="username!=null">
and username=#{username}
</if>
</where>
简化了之前动态sql拼接的where 1=1
如果where标签下含有条件成立的if,则会在sql语句中添加where,没有if就不添加。(有条件加where)
第一个if的sql拼接不会有 and。
注意(if标签):
if标签里可以有计算、方法,能被MyBatis识别——test的判断语句会作为java代码执行。
-
当传递对象是实体类对象时,在if标签test里,可以直接用属性来计算判断,如:username==‘李四’
-
当传递对象是字符串String等非对象类型时,不能随意的写参数去判断了(String里没有这些属性);MyBatis提供了一个变量来接收单值数据—"_parameter";
-
类似于不定参数,当参数就一个时,直接表示,当参数为多个时,通过_parameter.get(0)来获取第一个。
参数为多个对象时:
<if test='_parameter.get("0").name != null'>
<select id="findMany" parameterType="java.lang.String" resultType="user"> select * from user <where> <if test="_parameter == '李四'"> id = 1 </if> </where> </select>
2.1 如果是单个字符,会被识别为char类型,char类型运算会自动转成ascll数字。
test="_parameter == ‘a’"会报数字转换异常
解决:
-
test="_parameter == ‘a.toString()’"
-
外层用单引号,内层用双引号
test='_parameter == "李四"'
-
where+foreach
parameterType不管是数组还是集合list,都是parameterType=“list”。
在foreach里:
- 参数是数组:collection=“array”。
- 参数是集合:collection=“list”。
3.mybatis分页插件pageHelper
5.0以上版本,在mybatis中配置的是com.github.pagehelper.PageInterceptor类,不然会发生类转换异常。实际内部使用的还是PageHelper类(之前版本的配置类)。
private Dialect dialect;
private String default_dialect_class = "com.github.pagehelper.PageHelper";
不用配置方言,默认为mysql,
public class PageHelper extends PageMethod implements Dialect {
private PageParams pageParams;
private PageAutoDialect autoDialect;
参数配置方式,之前的name=“dialect”;
<!--指定方言-->
<property name="helperDialect" value="mysql"></property>
分页信息获取
PageHelper.startPage(1,4);
List<User> all = userMapper.findAll();
通过PageHelper.startPage(2,3);设定sql中的分页查询条件
但是运行时会查询总条数作为参数保存在page对象里。
虽然编译期查询数据是List,但分页插件处理包装后返回结果是Page类型
List<User> userList = userMapper.findAll();
//for (User user : all) {
// System.out.println(user);
// }
System.out.println(userList.getClass().getName());
System.out.println(userList);
//结果:
//com.github.pagehelper.Page
//Page{count=true, pageNum=2, pageSize=3, startRow=3, endRow=6, total=9, pages=3, reasonable=false, pageSizeZero=false}
//Page类
public class Page<E> extends ArrayList<E> implements Closeable
Page是一个ArrayList,List内置的数组来保存查询的结果(sql查询的原始List),含有带泛型的遍历器;通过定义的类属性来保存分页信息。
和之前手动封装的Page对象是一样的,通过两个Dao方法实现。
用查询出的集合(Page集合)来创建PageInfo对象(对Page对象包装了一下),获取分页数据
//分页数据获取
PageInfo<User> pageInfo = new PageInfo<User>(userList);
System.out.println("当前页"+pageInfo.getPageNum());
System.out.println("总条数"+pageInfo.getTotal());
System.out.println("总页数"+pageInfo.getPages());
4. PageHelper.startPage(1,4)为什么只能使用一次
PageHelper
方法使用了静态的 ThreadLocal
参数,分页参数和线程是绑定的。
只要你可以保证在 PageHelper
方法调用后紧跟 MyBatis 查询方法,这就是安全的。因为 PageHelper
在 finally
代码段中自动清除了 ThreadLocal
存储的对象。
如果pageHelper.startPage后没有跟MyBatis的查询方法,就是不安全的。PageHelper 生产了一个分页参数,但是没有被消费,这个参数就会一直保留在这个线程上。当这个线程再次被使用时,就可能导致不该分页的方法去消费这个分页参数,这就产生了莫名其妙的分页。
可以手动清理 ThreadLocal
存储的分页参数
List<Country> list;
if(param1 != null){
PageHelper.startPage(1, 10);
try{
list = countryMapper.selectAll();
} finally {
PageHelper.clearPage();
}
} else {
list = new ArrayList<Country>();
}
在执行了MyBatis查询后,PageHelper会清除ThreadLocal中的分页参数,所以要再分页查询,需要重写一个startPage()。
MyBatis-plus
https://www.jianshu.com/p/ceb1df475021
Mybatis-Plus(简称MP)是一个 Mybatis 的增强工具,在 Mybatis 的基础上只做增强不做改变,它已经封装好了一些crud方法,我们不需要再写sql语句、xml了,直接调用这些方法就行,就类似于JPA。
通过继承 BashMapper<>来实现,这个类里封装了可能用到的sql方法(注解sql)。
mapper:
public interface EmplopyeeDao extends BaseMapper<Employee> {
}
对于非普通的sql查询等,通过条件构造器(EntityWrapper)来完成
//查询gender为0且名字中带有老师、或者邮箱中带有a的用户:
List<Employee> employees = emplopyeeDao.selectList(
new EntityWrapper<Employee>()
.eq("gender",0)
.like("last_name","老师")
//.or()//和or new 区别不大
.orNew()
.like("email","a")
);
spring中的${}和#{}
-
在spring核心配置文件中通过${}来获取容器中的对象(例如:读取druid.properties)
<property name="driverClass" value="${jdbc.driver}"/>
-
在MyBatis里通过#{}来作为占位符,内部放置parameterType的属性
<insert id="save" parameterType="user"> insert into user values (#{id},#{username},#{password},#{birthday}) </insert>
spring里加载配置文件时的classpath
applicationContext.xml
<!--加载配置文件druid.properties-->
<context:property-placeholder location="classpath:druid.properties"/>
SqlMapConfig.xml
是在属性resource里加载的,所以不用写classpath:
<!--加载配置文件-->
<properties resource="druid.properties"></properties>
项目编译后,java类和resource包下的配置文件都编译在classes包下。可以理解为classpath(类路径)就是classes包下的配置文件。
WEB应用中的classpath专指项目WEB-INF/classes和WEB-INF/lib,web容器在启动时会对WEB-INF/classes和WEB-INF/lib目录下的class文件、配置文件以及jar文件进行加载,当然,配置文件的加载是根据web.xml中的配置(显示配置了文件路径或者配置了其它类而在类内部进行加载配置文件)来的,web容器并不会自动加载WEB-INF/classes下的配置文件。
JVM在运行时会产生3个ClassLoader:根装载器, ExtClassLoader(扩展类加载器)和AppClassLoader(应用类装载器)。其中,根装载器不是ClassLoader的子类,它使用C++语言编写,因而在java中看不到它,根装载器负责装载JRE的核心类库。ExtClassLoader和AppClassLoader都是ClassLoader的子类,其中ExtClassLoader负责装载JRE扩展目录ext中的JAR类包;AppClassLoader负责装载Classpath路径下的类包。
Spring加载Resource文件是通过ResourceLoader来进行的。
ResourceLoader接口只提供了classpath前缀的支持。而classpath*的前缀支持是在它的子接口ResourcePatternResolver中。
MyBatis注解映射:多个参数如何在定位符中区分
通过@Param注解来实现—接口方法形参和sql中占位符的映射。
/*@Param注解区分多个参数*/
@Select({"select * from user where username = #{name} and id = #{id}"})
User findByParams(@Param("name") String name,@Param("id") int id);
- 在xml配置里,同样可以使用@Param来实现,可以省略parameterType属性
User findByName(@Param("name") String name, @Param("id") int id);
xml里:
<!--多个参数、参数类型-->
<select id="findByName" resultType="user">
select * from user where username = #{name} and id = #{id}
</select>
Mybatis中的 ${} 和 #{}区别与用法
经常使用的是#{},相互区别:
1、#是预编译的方式,$是直接拼接;
2、#不需要关注数据类型,mybatis实现自动数据类型转换;$不做数据类型转换,需要自行判断数据类型;
3、#可以防止sql注入;$不能防止sql注入;
4、如果 parameterType 只有一个参数,默认情况下,#{ }中可以写任意的名字;${ }中只能用value来接收。
举个例子:
select * from student where student_name = #{name}
预编译后,会动态解析成一个参数标记符?:
select * from student where student_name = ?
而使用${}在动态解析时候,会传入参数字符串
参数para = “lyrics”
select * from student where student_name = ${para}
select * from student where student_name = ‘lyrics’