一、#与$的区别
- #{}:使用了预编译处理,底层就是使用PreparentStatment,安全。
- ${}:没有使用预编译处理,底层就是Statment,有SQL注入风险。
-- #{}的作用主要是替换预编译语句(PrepareStatement)中的占位符?:
-- 对于 :
INSERT INTO user (name) VALUES (#{name});
-- 相当于
INSERT INTO user (name) VALUES (?);
-- ${} 符号的作用是直接进行字符串替换:
-- 对于 :
INSERT INTO user (name) VALUES ('${name}');
-- 相当于
INSERT INTO user (name) VALUES ('zhangsan');
二、ResultMap(自定义结果映射)
常情况下,我们可能表字段和实体类的属性不一致,或者多表查询,都需要我们来配置一个返 回类型
1、在映射配置文件中配置:
<resultMap id="studentMapping" type="Student">
<!-- id:主键字段,底层会有优化 -->
<id column="id" property="id"/>
<!-- result:普通字段 -->
<result column="name" property="name"/>
<!-- 其它不指定列会自动匹配,通常把所有字段都写上 -->
<result column="age" property="age"/>
<result column="email" property="email"/>
</resultMap>
2、使用:
<select id="listMapping" resultMap="studentMapping">
select * from student
</select>
注意:resultType和resultMap不要同时使用。
3、Mybatis中javaType和jdbcType对应关系
jdbcType | JavaType |
---|---|
CHAR | String |
VARCHAR | String |
LONGVARCHAR | String |
NUMERIC | java.math.BigDecimal |
DECIMAL | java.math.BigDecimal |
BIT | boolean |
BOOLEAN | boolean |
TINYINT | byte |
SMALLINT | short |
INTEGER | int |
BIGINT | long |
REAL | float |
FLOAT | double |
DOUBLE | double |
BINARY | byte[] |
VARBINARY | byte[] |
LONGVARBINARY | byte[] |
DATE | java.sql.Date |
TIME | java.sql.Time |
TIMESTAMP | java.sql.Timestamp |
CLOB | Clob |
BLOB | Blob |
ARRAY | Array |
DISTINCT | mapping of underlying type |
STRUCT | Struct |
REF | Ref |
DATALINK | java.net.URL |
4、RestulType和ResultMap的区别?
- RestulType使用我们已经存在的实体类型(Pojo),使用RestulType的
前期是字段名和属性名要一致。 - RestulType不能用在关联查询上。
- ResultMap是我们自定义的一个结果映射,用法更加灵活,我们可以自己
来指定字段名和属性名的对应关系。 - ResultMap还可以来配置MyBatis中的关联查询。
三、分页查询
1、使用SQL的方式
Mapper接口中:
@Select("select * from student limit #{pageNum},#{pageSize}")
List<Student> listByPage(@Param("pageNum") int pageNum, @Param("pageSize") int pageSize);
测试类:
@Test
public void testListByPage(){
//打开会话
SqlSession session = sqlSessionFactory.openSession();
//查询Mapper(xxxMapper接口的类类型),返回的mapper就是接口的实现类(通过代理模式实现)
StudentMapper mapper = session.getMapper(StudentMapper.class);
//调用对象的方法
//当前页码
int pageNum=2;
//每页显示的数量
int pageSize=2;
List<Student> stus = mapper.listByPage((pageNum-1)*pageSize,pageSize);
//测试打印
System.out.println(stus);
//关闭会话
session.close();
}
2、使用MyBatis的方式
Mapper配置文件中:
<select id="listByPage2" resultMap="studentMapping">
select * from student
</select>
测试类:
@Test
public void testListPager2() {
int pagerNow = 2;//当前页
int pagerSize = 3;//每页显示几条
SqlSession session = MyBatisUtil.openSession();
RowBounds rowBounds = new RowBounds((pagerNow-1)*pagerSize, pagerSize);
List<Student> listPager = session.selectList("pagerList2",
null, rowBounds);
for (Student stu : listPager) {
System.out.println(stu);
}
session.close();
}
三、一对一关联
1、关联关系(association)
一对一: 人和身份证、丈夫和妻子…
2、MyBatis中使用association标签来解决一对一的关联查询,association标签可用的属性如下:
- property:对象属性的名称
- javaType:对象属性的类型
- column:所对应的外键字段名称
- select:使用另一个查询封装的结果
3、创建表和数据
-- 添加老师表
CREATE TABLE `teacher` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
)
-- 修改学生表,添加tid字段
ALTER TABLE student
ADD COLUMN tid INT(10);
-- 修改学生表,添加外键约束
ALTER TABLE student
ADD FOREIGN KEY(tid)
REFERENCES teacher(id);
4、创建Teacher实体类
package org.example.entity;
/**
* 教师实体类
*/
public class Teacher {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Teacher{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
5、修改Student实体类
package org.example.entity;
/**
* @description: 学生实体类
*/
public class Student {
//添加teacher属性,并生成getter()setter()方法
private Teacher teacher;
...
}
6、创建Mapper接口
1)TeacherMapper
public interface TeacherMapper {
//根据id查询教师
Teacher findById(int id);
}
2)StudentMapper
public interface StudentMapper {
//根据id查询学生
Student findById(int id);
}
7、创建Mapper映射配置
1)TeacherMapper
<?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="org.example.mapper.TeacherMapper">
<select id="findById" resultType="Teacher">
select * from teacher where id=#{id}
</select>
</mapper>
2)StudentMapper.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="org.example.mapper.StudentMapper">
<resultMap id="studentMapping" type="Student">
<!-- id:主键字段,底层会有优化 -->
<id column="id" property="id"/>
<!-- result:普通字段 -->
<result column="name" property="name"/>
<!-- 其它不指定列会自动匹配,通常把所有字段都写上 -->
<result column="age" property="age"/>
<result column="email" property="email"/>
<!-- 一对一关联关系:其实就是老师一的那一端
association:一对一
property:属性名
select:调用查询
column:参数关联哪列字段
-->
<association property="teacher" select="org.example.mapper.TeacherMapper.findById"
column="tid">
</association>
</resultMap>
<!--根据id查询学生-->
<select id="findById" resultMap="studentMapping">
select * from student where id=#{id}
</select>
</mapper>
8、测试类
1、需求:按id查询学生信息,并且显示老师的名称。
@Test
public void testFindById(){
//打开会话
SqlSession openSession = sqlSessionFactory.openSession();
//获取mapper
StudentMapper mapper = openSession.getMapper(StudentMapper.class);
//调用接口方法
Student stu = mapper.findById(1);
//输出学生信息
System.out.println(stu.getId()+","+stu.getName());
//输出老师信息
System.out.println(stu.getTeacher().getName());
}
四、配置延迟加载
在上述演示时,我们会发现不管是要学生信息,还是老师信息,都会去查2次,这样会影响查询 效率,在MyBatis中,可以设置延迟加载。
延迟加载,也可以称为懒加载或者按需加载。
只需要简单增加两个配置即可:
1、通用配置文件mybatis-config.xml
增加:
<!--设置选项-->
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
如果在已有全局配置下,对某个查询不需要延迟加载时,还可以再mapper映射中配置:
- fetchType:lazy 延迟加载(默认)
- fetchType:eager 立刻加载
2、配置映射文件设置:
<association property="teacher" select="org.example.mapper.TeacherMapper.findById"
column="tid" fetchType="lazy">
</association>
完整代码
代码已托管在gitee上面,点击直达