MybatisNotes
1.mybatis简介
- mybatis是一款持久层的框架,主要用于对JDBC的封装
- mybatis可以使用xml配置文件或者注解来配置和映射原生信息
- Mybatis官方文档:http://www.mybatis.org/mybatis-3/zh/index.html
2.mybatis的使用
1.导入相应的依赖包
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
<scope>provided</scope>
</dependency>
</dependencies>
2.配置mybatis配置文件,mybatis.xml文件的标签是有顺序的
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--配置mybatis运行环境-->
<!--启用log4j日志-->
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<!--起别名-->
<typeAliases>
<package name="cn.ty.pojo"/>
</typeAliases>
<!--数据连接-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatisTest? useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--注册UserMapper.xml-->
<mappers>
<mapper resource="cn/ty/mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>
3.编写实体类,属性与数据库列名一致
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private int age;
}
4.创建mapper接口与对应的xml文件,并将其注册到mybatis.xml文件中
//查询全部用户信息
List<User> queryAllUser();
}
<?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="cn.ty.mapper.UserMapper">
<!-- 注意这里的id要与接口的方法名相同 -->
<select id="queryAllUser" resultType="user">
select *from user
</select>
</mapper>
这条sql语句相当于原生jdbc中的
String sql = select *from user;
PreparedStatement ps = conn.prepareStatement(sql);
5.测试,SqlSession 提供了在数据库执行 SQL 命令所需的所有方法,获得SqlSession,可以将其封装成一个工具类
//获得SqlSessionFactory对象
private static SqlSessionFactory sqf;
static {
String resource = "mybatis.xml";
InputStream ips = GetSession.class.getClassLoader().getResourceAsStream(resource);
sqf = new SqlSessionFactoryBuilder().build(ips);
}
//获得SqlSession
public static SqlSession getSession(){
return sqf.openSession();
}
}
使用junit进行测试
public class MybatisTest01 {
@Test
public void test(){
SqlSession session = GetSession.getSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
List<User> users = userMapper.queryAllUser();
for (User user:users) {
System.out.println(user);
}
}
}
3.mapper.xml文件
-
mapper中主要用于数据库操作,对应select、delete、update、insert标签,每写完一个mapper.xml文件都要注册到mybatis.xml文件中
-
parameterType:方法参数类型 ,参数名要与实体类中一致,若不一致用@Param("属性名")来标识
1.基本数据类型和String类型,要与接口方法参数对应 <select id="queryByName" parameterType="String" resultType="user"> select *from user where name=#{name} </select> 2.包装类Integer、Long、Double等用 parameterType="java.lang.Long" 3.javaBean类型 <update id="update" parameterType="user"> update user set name= #{name},age = #{age} where id = #{id} </update> 4.若有多个参数则可省略parameterType属性,可以用arg获取参数,0表示第一个参数 <select id="findByNameAndAge" resultType="user"> select * from user where name= #{arg0} and age = #{arg1} </select 5.map集合类型,如用于分页查询时传入一个Map集合 接口方法:` List<User> queryByPage(Map<String,Integer> map);` <select id="queryByPage" parameterType="map" resultType="user"> select *from user limit #{startIndex},#{pageSize} </select> 测试: @Test public void test04(){ SqlSession session = GetSession.getSession(); UserMapper userMapper = session.getMapper(UserMapper.class); Map<String,Integer> map = new HashMap<>(); map.put("startIndex", 0); map.put("pageSize", 2); List<User> users = userMapper.queryByPage(map); for (User user: users) { System.out.println(user); } } //map传入的key的名称一定要与sql中的对应 -
${}和#{}获取参数的区别
1、#相当于对数据 加上 双引号,$相当于直接显示数据。 2、#{} : 根据参数的类型进行处理,比如传入String类型,则会为参数加上双引号。#{} 传参在进行SQL预编译时,会把参数部分用一个占位符 ? 代替,这样可以防止 SQL注入。 3、${} : 将参数取出不做任何处理,直接放入语句中,就是简单的字符串替换,并且该参数会参加SQL的预编译,需要手动过滤参数防止 SQL注入。 4、因此 mybatis 中优先使用 #{};当需要动态传入表名或列名时,再考虑使用 ${},$他的应用场景是需要动态传入表名或列名时使用,MyBatis排序时使用order by排序时使用$ -
resultType:结果类型
1.基本数据类型和String类型,增删改返回值类型都为int类型,可以省略 <select id="queryNameById" parameterType="int" resultType="String"> select name from user where id=#{id} </select> 2.包装类Integer、Long、Double等 //统计用户总数 Integer queryCount(); <select id="queryCount" resultType="Integer"> select count(id) from user </select> 3.javaBean类型 <select id="findByNameAndAge" resultType="user"> select * from user where name= #{arg0} and age = #{arg1} </select -
resultMap
1.多对一关系 表结构:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private int id;
private String name;
private Teacher teacher;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
private int id;
private String name;
}
StudentMapper:
//查询全部学生及其对应老师的信息
List<Student> queryStudentAndTeacher();
StudentMapper.xml:
<!--多对一,结果嵌套查询-->
<select id="queryStudentAndTeacher" resultMap="studentTeacher">
-- 单独这句sql查出的teacher属性为null
select s.id sid,s.name sname ,t.id tid ,t.name tname from student s,teacher t where s.tid=t.id
</select>
<!--id为resultMap的值 type是上面语句要查出的对象-->
<resultMap id="studentTeacher" type="student">
<!--主键用id标签,其余用result标签-->
<id property="id" column="sid"></id>
<result property="name" column="sname"></result>
<!--property为pojo中的属性名 ,javaType指pojo中特定的属性的类型 -->
<association property="teacher" javaType="teacher">
<id property="id" column="tid"></id>
<result property="name" column="tname"></result>
</association>
</resultMap>
<!--======================================-->
<!--多对一,查询嵌套处理 类似与子查询-->
<select id="queryStudentAndTeacher2" resultMap="studentTeacher2">
select *from student
</select>
<select id="queryTeacher" resultType="teacher">
select *from teacher where id=#{tid}
</select>
<resultMap id="studentTeacher2" type="student">
<!-- 属性名与数据库列名一致,这里可以省略id和result标签-->
<!--property是pojo中的属性,column为表中的列名,javaType是属性的类型,select是从queryTeacher这个查询语句中进行子查询,比结果嵌套查多了column-->
<association property="teacher" column="tid" javaType="teacher" select="queryTeacher">
</association>
</resultMap>
2.一对多关系
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student1 {
private int id;
private String name;
private int tid;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher1 {
private int id;
private String name;
List<Student1> student1;
}
Teacher1Mapper:
public interface Teacher1Mapper {
//查询所有老师及其学生的信息
List<Teacher1> queryTeacherAndS();
//查询所有老师及其学生的信息
List<Teacher1> queryTeacherAndS1();
}
Teacher1Mapper.xml:
<!--一对多,结果嵌套查询-->
<select id="queryTeacherAndS" resultMap="teacherStudent">
select t.id tid ,t.name tname,s.name sname from teacher1 t,student1 s where t.id=s.tid order by tid
</select>
<resultMap id="teacherStudent" type="teacher1">
<id property="id" column="tid"></id>
<result property="name" column="tname"></result>
<!--对象用association,集合用collection 结集合中的泛型用ofType获取-->
<collection property="student1" ofType="Student1">
<result property="name" column="sname"></result>
</collection>
</resultMap>
<!--======================================-->
<!--一对多 ,子查询-->
<select id="queryTeacherAndS1" resultMap="teacherStudent1">
select *from teacher1
</select>
<select id="queryStudent" resultType="student1">
select *from student1 where tid =#{id}
</select>
<resultMap id="teacherStudent1" type="teacher1">
<!--property为pojo里的属性名,column时要传入子查询的类名 javaType是pojo属性类型 ofType为集合泛型类型-->
<collection property="student1" column="id" javaType="ArrayList" ofType="student1" select="queryStudent"></collection>
</resultMap>
4.动态sql
- if标签
<select id="queryByIdAndAge" resultType="user">
select *from user where
<if test="id!=0">
id=#{id}
</if>
<if test="age!=0">
and age=#{age}
</if>
</select>
根据条件表达式的结果来判断是否将对应的语句加入到sql中,但是如果id为0且age不为0的话,sql中where后紧跟着and会出错,所以if常与where标签一起使用
- where标签
<select id="queryByIdAndAge1" resultType="user">
select *from user
<where>
<if test="id!=0">
id=#{id}
</if>
<if test="age!=0">
and age=#{age}
</if>
</where>
</select>
where标签会自动判断是否删除sql中的and关键字,若and与where直接相连则删除and
- choose、when、otherwise标签
<select id="queryUser" resultType="user">
select * from user
<where>
<choose>
<when test="id!=0">
id=#{id}
</when>
<when test="name!=null">
name=#{name}
</when>
<when test="age!=0">
age=#{age}
</when>
<otherwise>
</otherwise>
</choose>
</where>
</select>
choose是or的含义,当满足when标签的一个时则choose结束,全不满足时执行<otherwise>标签,if时and的含义,只要test表达式为真就执行
- trim标签
trim标签中的prefix和suffix属性会被用与生成实际的sql语句,如果语句前后出现了prefixOverrides或者suffixOverrides属性中的值,会将其自动删除
<select id="findByUser" parameterType="User" resultType="User">
select * from user
<trim prefix="where" prefixOverrides="and">
<if test="id!=0">
id = #{id}
</if>
<if test="name!=null">
and name = #{name}
</if>
<if test="age!=0">
and age = #{age}
</if>
</trim>
</select>
- set标签
set标签主要用与update操作
<update id="update" parameterType="cn.ty.user">
update user
<set>
<if test="name!=null">
name = #{name},
</if>
<if test="age!=0">
age = #{age}
</if>
</set>
where id = #{id}
</update>
- foreach标签
mapper:
//遍历查询student
List<Student> queryStudentForeach(Map map);
mapper.xml
<select id="queryStudentForeach" parameterType="map" resultType="student">
select *from student
<where>
-- collection要遍历的集合名称,相当于select *from student where(id=? or id=?)
<foreach collection="ids" item="id" open="(" close=")" separator="or">
id=#{id}
</foreach>
</where>
</select>
测试:
@Test
public void test11(){
SqlSession session = GetSession.getSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
Map map = new HashMap();
List ids = new ArrayList();
ids.add(1);
ids.add(2);
map.put("ids", ids);
List<Student> students = mapper.queryStudentForeach(map);
for (Student student : students) {
System.out.println(student);
}
session.close();
}
5.二级缓存
是基于一个namespace的,不同的mapper共用一个缓存
开启步骤:
1.在mybatis.xml中开启全局缓存
` <setting name="cacheEnabled" value="true"/>`
2.在mapper.xml中配置缓存信息 <cache/>
6.mybatis运行原理
首先由Resources加载全局配置文件,然后new 一个SqlSessionFactoryBuilder对象,它是SqlSessionFactory的构建者,由SqlSessionFactory的实现类DefaultSqlSessionFactory实例化一个 对象,在实例化之前由XMLConfigbuilder解析全局配置文件,并将解析的结果放入Configuration中,然后把 Configuration传入DefaultSqlSessionFactory中,到此SqlSessionFactory工厂创建完成,再由工厂创建SqlSession,每次创建SqlSession时,都需要由TransactionFactory 创建Transaction对象,同时还要创建SqlSession的执行器Excutor,最后实例化DefaultSqlSession,传递给SqlSession接口。

浙公网安备 33010602011771号