# 简单查询

驼峰命名配置:

一般数据库的字段名都是下划线分隔,但是 Java 里面是驼峰命名,就会导致查询时数据库的字段映射不到 Java 类里面,所以需要开启转换

<settings>
	<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

对于查询结果,我们可以做如下更改:

  • 查询结果映射为实体类
<select id="studentList" resultType="Student">
    select * from student
</select>
  • 查询结果映射为 Map
<select id="selectStudent" resultType="Map">
    select * from student
</select>

其中一个 Map 就是一查询结果,当然,对应的 mapper 接口方法就需要换成:

public interface TestMapper {
    List<Map> selectStudent();
}
  • 指定映射规则
<resultMap id="Map" type="Student">
    <result column="sid" property="sid"/>
    <result column="name" property="name"/>
</resultMap>
<select id="selectStudent" resultType="Map">
    select * from student
</select>
  • 指定构造器
<resultMap id="Map" type="Student">
    <constructor>
        <arg column="sid" javaType="Integer"/>
        <arg column="name" javaType="String"/>
    </constructor>
</resultMap>
<select id="selectStudent" resultType="Map">
    select * from student
</select>

但是查询一般会附带条件,所以 select 标签除了 resultType 之外,还需要 parameterType 标签:

<select id="getStudentBySid" parameterType="int" resultType="Student">
    select * from student where sid = #{sid}
</select>

通过使用 #{xxx} 或是 ${xxx} 来填入我们给定的属性,实际上 Mybatis 本质也是通过 PreparedStatement 首先进行一次预编译,有效地防止 SQL 注入问题,但是如果使用 ${xxx} 就不再是通过预编译,而是直接传值,因此我们一般都使用 #{xxx} 来进行操作。

其实插入,删除这些需要传递参数的语句都会用到 #{}

# 复杂查询

# 一对多

一个老师可以教授多个学生,需要一次性将 A 老师的学生全部映射给 A 老师的对象:

@Data
public class Teacher {
    int tid;
    String name;
    List<Student> studentList;
}

之前编写的都是非常简单的映射,此时需要使用 resultMap 来自定义映射规则。

<select id="getTeacherByTid" resultMap="asTeacher">
        select *, teacher.name as tname from student 
            inner join teach on student.sid = teach.sid                          
            inner join teacher on teach.tid = teacher.tid where teach.tid = #{tid}
</select>
<!--teach 是中间表,连接学生和老师两张表 -->
<resultMap id="asTeacher" type="Teacher">
    <id column="tid" property="tid"/>
    <result column="tname" property="name"/>
    <collection property="studentList" ofType="Student">
        <id property="sid" column="sid"/>
        <result column="name" property="name"/>
        <result column="sex" property="sex"/>
    </collection>
</resultMap>

<resultMap>id 要与 <select> 标签相关联。

之前说过,实际项目中联表查询有时会非常复杂,所以有时会直接选择手写 sql 语句使用 jdbc 而不是使用 Mybatis。

# 多对一

现在修改一下 StudentTeacher 两个类:

@Data
@Accessors(chain = true)
public class Student {
    private int sid;
    private String name;
    private String sex;
    private Teacher teacher;
}
@Data
public class Teacher {
    int tid;
    String name;
}

我们想要通过某个条件查询学生数据,每一行学生都要顺带查询老师的信息,导致出现多对一查询:

<select id = "test" resultMap = "sTot">
	select * , teacher.name as tname from Student
    	left join teach on teach.sid = student.sid
    	left join teacher on teach.tid = teacher.tid
</select>
<!-- 查询结果里面不需要写 teacher.tid,因为学生表中有 -->
<resultMap id = "sTot" type="Student">
	<id column="sid" property="sid"/>
    <result column="name" property="name"/>
    <result column="sex" property="sex"/>
    <association property="teacher" javaType="Teacher">
    	<id column="tid" property="tid"/>
        <result column="tname" property="name"/>
    </association>
</resultMap>

其实不论是用 <collection> 还是 <association> ,都是对查询结果的一种处理方式罢了。

# 事务

因为内容比较少,就放到复杂查询里面一起讲解。

我们使用 Mybatis,在 Java 代码层面是使用 SqlSession ,其实打开一个 SqlSession ,相当于打开了一个事务,如果关闭了自动提交,在调用了修改数据库的语句,就需要 commit

try (SqlSession sqlSession = MybatisUtil.getSession(false)){
    TestMapper testMapper = sqlSession.getMapper(TestMapper.class);
    testMapper.addStudent(new Student().setSex("男").setName("小王"));
    testMapper.selectStudent().forEach(System.out::println);
    
    // 回滚
    sqlSession.rollback();
    // 提交
    sqlSession.commit();
}

# 参考

https://www.yuque.com/qingkongxiaguang/javaweb/gn0syt#3203fe15