1. <typeAliases>标签(配置别名)
功能:用于给 java 类型定义别名, 方便在配置文件中使用.
使用方式一
<!-- typeAliases给类型起别名 -->
<typeAliases>
<!-- 给User类起别名为u -->
<typeAlias type="com.bjsxt.pojo.User" alias="u" />
</typeAliases>
使用方式二
<typeAlias>中, 可以省略 alias 属性, 表示类别名为类名, 大小写不敏感
<typeAliases>
<!-- 给User类起别名, 别名为user -->
<typeAlias type="com.bjsxt.pojo.User" />
</typeAliases>
使用方式三
可以通过<package>给整个包下的所有类定义别名为类名
<typeAliases>
<!-- 给包下的所有类定义别名为类名 -->
<package name="com.bjsxt.pojo" />
</typeAliases>
常见的MyBatis 的内建别名
2 配置parameterType属性进行参数的传递
2.1 parameterType的使用环境
如果执行的是条件查询, 需要在调用方法时传参数进来, 此时, 可以在 select 标签中通过 parameterType 属性指定参数的类型. 而在 SQL 语句中, 可以通过#{}的方式获取参数.
2.2一个参数的查询
注意点:当只有一个参数时, #{}中可以任意填写
#{}用于获取参数
index, 索引, 从0开始
param+数字, param1, param2
实例
根据 id 查询用户信息.
<?xml version="1.0" encoding="UTF-8"?>
<!-- parameterType, 参数类型, 用于参数的传递 -->
<select id="selById" resultType="user" parameterType="int">
select * from t_user where id=#{param1}
</select>
2.3多个参数的查询
多个参数的查询多个参数传递时, 由于 sqlSession 中提供的查询方法只允许传入一个参数, 因此可以对多个参数进行封装. 可以使对象或 Map 集合
2.3.1 封装为对象
select id="sel" resultType="user" parameterType="user">
<!-- 如果参数是对象, 可以通过#{属性名}来获取 -->
select * from t_user where username=#{username} and
password=#{password}
</select>
2.3.2封装为Map集合
<select id="sel" resultType="user" parameterType="map">
<!-- 如果参数是map, 可以通过#{key}来获取 -->
select * from t_user where username=#{uname} and password=#{upwd}
</sele
public void sel() {
SqlSession session = null;
try {
session = new SqlSessionFactoryBuilder()
.build(Resources.getResourceAsStream("mybatis-cfg.xml"))
.openSession();
User u = new User();
u.setUsername("zhangsan");
u.setPassword("123");
User user =
session.selectOne("com.bjsxt.mapper.UserMapper.sel", u);
System.out.println(user);
} catch (IOException e) {
e.printStackTrace();
} finally {
session.close();
}
}
3 MyBatis事务管理
3.1 事务(Transaction)
a) 事务是数据库操作的最小单元, 有 ACID 的特性. 应该保证一个事务的的 SQL 语句要么同时成功, 要么都不成功.
b) MyBatis 中配置了事务管理器, type 属性设置为 JDBC.表示 MyBatis 采用和原生 JDBC 相同的事务管理机制.
c) 在 MyBatis 执行的开始时,将自动提交功能关闭了.所以,在执行 DML 操作时, 需要手动提交事务.
3.2 新增(insert)
mapper 文件中, 通过<insert>定义新增语句.
注意, 由于DML 操作的返回值都是 int 类型, 所以, 不需要定义resultType 属性.
<!-- 新增 -->
<insert id="insUser" parameterType="user">
insert into t_user values (default, #{username}, #{password})
</insert>
测试
@Test
public void testIns() {
SqlSession session = MyBatisUtil.getSession();
User user = new User();
user.setUsername("小明");
user.setPassword("123");
int num = session.insert("com.bjsxt.mapper.UserMapper.insUser",
user);
if(num > 0) {
// 提交事务
session.commit();
System.out.println("SUCCESS!");
} else {
// 回滚事务
4 MyBatis接口绑定方案
MyBatis 中, 提供了一套接口绑定方案. 程序员可以提供一个 接 口 , 然 后 提 供 对 应 接 口 的 一 个 mapper.xml 文 件 .
MyBatis 会自动将接口和 xml 文件进行绑定. 实际上就是MyBatis 会根据接口和对应的 xml 文件创建接口的实现类.换言之, 就是可以得到接口类型的对象, 方便方法的调用.
4.1使用方法
1) 定义接口
2)编写对应接口的映射文件
3) 在核心配置文件中扫描接口
4)应用
1 定义接口
public interface UserMapper {
List<User> selAll();
}
2 编写对应接口的映射文件
注意:
a)xml 文件名要和接口名一致
b)namespace 属性必须为接口的全限定路径
c)id 属性必须和接口对应的方法名一致
<mapper namespace="com.bjsxt.mapper.UserMapper">
<select id="selAll" resultType="User">
select * from t_user
</select>
</mapper>
3 在核心配置文件中扫描接口
扫描单个接口, 可以使用 mapper 标签的 class 属性
<mappers>
<mapper class="com.bjsxt.mapper.UserMapper" />
</mappers>
当扫描多个接口时,为简化配置,可以使用 package 标签,表示扫描对应包下的所有接口
<mappers>
<package name="com.bjsxt.mapper" />
</mappers>
4 应用
在使用时, 可以通过 SqlSession 对象的 getMapper 方法,得到接口的代理对象, 从而可以调用定义好的方法
@Test
public void testBind() {
SqlSession session = MyBatisUtil.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> list = mapper.selAll();
for (User user : list) {
System.out.println(user);
}
session.close();
}
4.2 接口绑定解决多参数的传递
方式一
接口中定义方法
User selByUP(String username, String password
映射文件中提供对应的标签. 此时, SQL语句中获取方式有两种, 通过#{index}或#{param+数字}的方式
<select id="selByUP" resultType="user">
select * from t_user where username=#{0} and password=#{1}
</select>
方式二
接口中定义方法, 参数中使用@Param 注解设定参数名用于在 SQL 语句中使用
User selByUP(@Param("username") String username, @Param("password")
String password);
映射文件中提供对应的标签. 此时, SQL语句中获取方式有两种, 通过#{参数名称}或#{param+数字}的方式
<select id="selByUP" resultType="user">
select * from t_user where username=#{username} andpassword=#{password}
</select>
5 动态 SQL
根据条件的不同, SQL 语句也会随之动态的改变,比如用户名,密码两个条件,就有四种情况解决SQL 字符串在一起时的错误,如忘了空格或在列表的最后省略逗号之类的
5.1动态SQL常用的标签
<if/><where/>
<choose/><when/><otherwise/>
<trim/><bind/>
<foreach/><sql/><include/>
5.2 动态SQL <if> where>
<if>
用于进行条件判断, test 属性用于指定判断条件. 为了拼接条件, 在 SQL 语句后强行添加 1=1 的恒成立条件.
<where>
用于管理 where 子句. 有如下功能:
a)如果没有条件, 不会生成 where 关键字
b)如果有条件, 会自动添加 where 关键字
c)如果第一个语句是and开头,会自动去除and
示例
<select id="sel" resultType="Student">
select * from test
<where>
<if test="id>0">
and id=#{id}
</if>
<if test="name!=null and name!=''">
and name=#{name}
</if>
</where>
</select>
5.3 动态SQL <choose><when><otherwise> <set>
多个条件的判断的时候使用,功能类似于 switch...case...
5.3. 1<choose><when><otherwise>
示例
<select id="sel" resultType="user">
select * from t_user
<where>
<choose>
<when test="username != null and username != ''">
and username = #{username}
</when>
<when test="password != null and password != ''">
and password = #{password}
</when>
<otherwise>
and 1=1
</otherwise>
</choose>
</where>
</select>
5.3.2 <set>
用于维护 update 语句中的 set 子句. 功能如下:
a)满足条件时, 会自动添加 set 关键字
b)会去除 set 子句中多余的逗号
c)不满足条件时, 不会生成 set 关键字
int updUser(User user)
<update id="updUser" parameterType="user">
update t_user
<set>
id=#{id}, <!-- 防止所有条件不成立时的语法错误 -->
<if test="username != null and username != ''">
username=#{username},
</if>
<if test="password != null and password != ''">
password=#{password},
</if>
</set>
where id=#{id}
</update>
5.4 动态SQL<trim> <bind>
<trim>
用于在前后添加或删除一些内容
prefix: 前缀, 表示向前面添加内容
prefixOverrides: 从前面删除内容
suffix: 后缀, 表示向后面添加内容
suffixOverrides: 从后面删除内容
示例
<update id="updUser" parameterType="user">
update t_user
<trim prefix="set" prefixOverrides="user" suffix="hahaha"
suffixOverrides=",">
username=#{username},
</trim>
where id=#{id}
</update>
<bind>
用于对数据进行再加工, 用于模糊查询
<select id="sel" resultType="user">
select * from t_user
<where>
<if test="username!=null and username!=''">
<bind name="username" value="'%' + username + '%'"/>
and username like #{username}
</if>
</where>
</select>
5.5 动态SQL <foreach> <sql><include>
<foreach>
用于在 SQL 语句中遍历集合参数, 在 in 查询中使用
a)collection: 待遍历的集合
b)open: 设置开始符号
c)item: 迭代变量
d)separator: 项目分隔符
e)close: 设置结束符号
<select id="selIn" parameterType="list" resultType="user">
select * from t_user where id in
<foreach collection="list" open="(" separator="," close=")"
item="item">
#{item}
</foreach>
</select>
接口中的方法(可以设置别名来方便使用List)
List<User> selIn(@Param("list") List<Integer> list);
<sql><include>
<sql>用于提取 SQL 语句, <include>用于引用 SQL 语句
<sql id="mySql">
id, username, password
</sql>
<select id="selIn" parameterType="list" resultType="user">
select
<include refid="mySql"/>
from t_user where id in
<foreach collection="list" open="(" separator="," close=")"item="item">
#{item}
</foreach>
</select>
6 MyBatis 的缓存机制
a)缓存用于提高查询的效率
b)MyBatis的缓存是使用SQL标签的ID作为缓存的唯一标识的. 执行相同的标签可以使用缓存. 不同的标签不能使用缓存
c) MyBatis 中有两种缓存机制
1 一级缓存
a)默认开启. 线程级别的缓存, SqlSession 的缓存
b)在一个 SqlSession 生命周期中有效. SqlSession 关闭,缓存清空.
1 二级缓存
a)进程级别的缓存, SqlSessionFactory 的缓存
b)在一个 SqlSessionFactory 生命周期中有效.可以在多个SqlSession 生命中期中共享.
c)默认关闭, 需要使用的时候, 要为某个命名空间开启二级缓存(在 mapper.xml 中配置<cache>)
7 解决列名和属性名不一致问题
方式一
列别名
查询时, 可以通过列别名的方式将列名和属性名保持一致,继续使用自动映射, 从而解决该问题. 但是较为麻烦
<select id="selAll" resultType="user">
select id id1, username username1, password password2 from t_user
</select>
方式二
使用<resultMap>
<resultMap>用于自定义映射关系, 可以由程序员自主制定列名和属性名的映射关系. 一旦使用 resultMap, 表示不再采用自动映射机制
id用于映射主键
result用于非主键映射
<resultMap type="user" id="umap">
<id column="id" property="id1" />
<result column="username" property="username1" />
<result column="password" property="password1" />
</resultMap>
<select id="selAll" resultMap="umap">
select * from t_user
</select>
8 多表关联查询_设计表结构
1 MyBatis实现多表关联查询的方式
业务装配方式
n+1方式
关联方式
1.1业务装配实现多表查询(多对一)
mapper 层只做单表查询操作, 在 service 层进行手动装配,实现关联查询的结果
注意在创建实体类的时候添加另一个表格的对象作为属性
1.1.2示例
mapper 层
学生:
<mapper namespace="com.bjsxt.mapper.StudentMapper">
<select id="selAll" resultType="student">
select * from t_student
</select>
</mapper>
班级:
<mapper namespace="com.bjsxt.mapper.ClazzMapper">
<select id="selById" resultType="clazz" parameterType="int">
select * from t_class where id=#{0}
</select>
</mapper>
service 层
调用 mapper 层, 先查询所有学生, 再根据每个学生的班级编号查询班级信息, 手动进行组装, 称之为业务装配
public class StudentServiceImpl implements StudentService {
@Override
public List<Student> selAll() {
SqlSession session = MyBatisUtil.getSession();
// 学生mapper
StudentMapper stuMapper = session.getMapper(StudentMapper.class);
// 班级mapper
ClazzMapper clsMapper = session.getMapper(ClazzMapper.class);
// 查询所有学生信息
List<Student> list = stuMapper.selAll();
// 为每一个student组装班级信息
for (Student student : list) {
student.setClazz(clsMapper.selById(student.getCid()));
}
session.close();
return list;
}
}
2 resultMap的N+1方式实现多表查询(多对一)
2.1 mapper 层
<association>用于关联一个对象
property: 指定要关联的属性名
select: 设定要继续引用的查询, namespace+id
column: 查询时需要传递的列
提供 StudentMapper 和 ClazzMapper, StudentMapper 查询所有学生信息, ClazzMapper 根据编号查询班级信息. 再StudentMapper 中使用<association>设置装配
学生:
<mapper namespace="com.bjsxt.mapper.StudentMapper">
<resultMap type="student" id="smap">
<!-- N+1查询时, 同名映射可以省略, 但是只能使用一次 -->
<result property="cid" column="cid" />
<!-- 用于关联一个对象 -->
<association property="clazz" select="com.bjsxt.mapper.ClazzMapper.selById" column="cid">
</association>
</resultMap>
<select id="selAll" resultMap="smap">
select * from t_student
</select>
</mapper>
班级:
<mapper namespace="com.bjsxt.mapper.ClazzMapper">
<select id="selById" resultType="clazz" parameterType="int">
select * from t_class where id=#{0}
</select>
</mapper>
2.2 service 层
由于装配已经完成, service 层只需要调用 mapper 即可, 不需要再进行装配了
public class StudentServiceImpl implements StudentService {
@Override
public List<Student> selAll() {
SqlSession session = MyBatisUtil.getSession();
// 学生mapper
StudentMapper stuMapper = session.getMapper(StudentMapper.class);
List<Student> list = stuMapper.selAll();
session.close();
return list;
}
}
3 resultMap 的关联方式实现多表查询(多对一)
3.1 mapper 层
a)在 StudentMapper.xml 中定义多表连接查询 SQL 语句, 一次性查到需要的所有数据, 包括对应班级的信息.
b)通过<resultMap>定义映射关系, 并通过<association>指定对象属性的映射关系. 可以把<association>看成一个<resultMap>使用. javaType 属性表示当前对象, 可以写全限定路径或别名
<resultMap type="student" id="smap">
<id property="id" column="sid" />
<result property="name" column="sname" />
<result property="age" column="age" />
<result property="gender" column="gender" />
<result property="cid" column="cid" />
<association property="clazz" javaType="clazz">
<id property="id" column="cid" />
<result property="name" column="cname" />
<result property="room" column="room" />
</association>
</resultMap>
<select id="selAll" resultMap="smap">
select s.id sid, s.name sname, s.age, s.gender, c.id cid,c.name cname, c.room from t_student s left join t_class c on s.cid=c.id
</select>
9 注解开发详解
1 注解简介
a)注解是用于描述代码的代码. 例如: @Test(用于描述方法进行 junit 测试), @Override(用于描述方法的重写),@Param(用于描述属性的名称)
b)注解的使用风格: @xxx(属性), 使用前必须先导包
c)使用注解一般用于简化配置文件. 但是, 注解有时候也不是很友好(有时候反而更麻烦), 例如动态 SQL.
d)关于注解的属性
属性的设定方式是: 属性名=属性值
e)关于属性值的类型
基本类型和 String, 可以直接使用双引号的形式数组类型, name={值 1, 值 2, ...}; 如果数组元素只有一个, 可以省略大括号
对象类型, name=@对象名(属性) 如果属性是该注解的默认属性, 而且该注解只配置这一个属性, 可以将属性名省略
f)注解和配置文件可以配合使用
2 注解的使用
直接在方法上一行声明SQL语句
public interface StudentMapper {
@Select("select * from t_student")
List<Student> selAll();@Insert("insert into t_student values (default, #{name}, #{age},#{gender},#{cid})")
int insStu(Student student);
@Update("update t_student set age=#{1} where id=#{0}")
int updStu(int id, int age);
@Delete("delete from t_student where id=#{0}")
int delStu(int id);
}
3 @Results和@Result
@Results: 类似于<resultMap>
@Result: 类似于<resultMap>的子标签
3.1 通过注解实现多表关联查询
班级:
public interface ClazzMapper {
@Select("select * from t_class where id=#{0}")
Clazz selById(int id);
}
学生:
public interface StudentMapper {
@Select("select * from t_student")
@Results(value = {
@Result(column="id", property="id", id=true),
@Result(column="name", property="name"),
@Result(column="age", property="age"),
@Result(column="gender", property="gender"),
@Result(column="cid", property="cid"),
@Result(property="clazz", one=@One(select="com.bjsxt.mapper.ClazzMapper.selById"), column="cid")
})
List<Student> sel();
}