默认情况下, MyBatis会进行自动映射(Auto-Mapping), 指的是MyBatis能够自动将同名的列和属性进行映射
SQL语句复用度低 无法处理多变关联查询问题
在MyBatis核心配置文件中开启自动驼峰命名, 当MyBatis发现有带下划线的列名时, 会自动转换为对应的驼峰命名.
例如: reg_time --> regTime.
注意: settings标签要配置在environments标签的前面.
映射关系可以在多处使用 可以处理数据库表格之间一对一 一对多 多对多的关系
三个常用的查询方法: selectList, selectOne和selectMap, 都允许在调用的时候传递参数, 参数的类型是Object, 个数只能传递一个. 如果需要传递多个参数, 需要处理成单个对象. 同时, SQL语句也需要相应的修改, 要使用占位符替代接收的参数.
用于查询多条数据, MyBatis会自动将查到的数据封装为List集合.
最常用, 查不到时返回空集合, 而不是null.
用于查询单条数据, 结果是指定的某个对象或者某个值. 很常用. 底层调用了selectList, 如果查到一个值, 直接返回结果,
如果查到多个值, 抛出异常, 如果查不到, 返回null.
用于将查询结果转换为Map集合, 使用时需要指定将结果中的哪个属性作为map的key, Map的value就是当前对象.
一般不用. 底层调用selectList.
占位符有两种, 分别是#{}, ${}.
#{}底层使用的是PreparedStatement, ${}底层使用的是Statement.
#{}作为SQL语句占位符时, MyBatis允许接收三种类型的参数:
1)简单类型的参数
简单类型指的是基本数据类型, 包装类型, String, java.sql.*...,
此时, #{}会忽略占位符的名称和个数, 将参数进行绑定. parameterType可以指定参数的类型, 如果省略, 表示参数类型为Object.
一旦指定, 传参时必须类型一致, 否则抛出类型转换异常.
@Test
public void testSelById() {
SqlSession session = MyBatisUtil.getSession();
session.selectOne("selById", 3);
session.close();
}
2)Map类型的参数
多个参数传递时使用, 将多个参数封装为Map集合, #{}需要使用Map中对应的key去取值, 如果key不存在, 不会报错, 拿到的是null
@Test
public void testSel4LoginByMap() {
SqlSession session = MyBatisUtil.getSession();
Map params = new HashMap<>();
params.put("uname", "lisi");
params.put("upwd", "123");
session.selectOne("sel4Login", params);
session.close();
}
3)POJO类型的参数
多个参数封装为对应的POJO类, 此时, #{}需要调用该POJO类中对应的 getter 方法取值, 如果没有对应的getter, 则抛出异常.
@Test
public void testSel4LoginByPojo() {
SqlSession session = MyBatisUtil.getSession();
User user = new User();
user.setUsername("wangwu");
user.setPassword("123");
session.selectOne("sel4Login", user);
session.close();
}
当SQL语句结构不确定时, 不能使用#{}占位符,
原因是#{}底层使用的是PreparedStatement, 会对SQL语句进行预编译, 导致SQL语句的结构无法被补全.
使用${}来进行操作.
${}底层使用的是Statement实现, 做的是字符串的直接拼接.
SQL语句结构固定的情况下, 应该使用#{}占位符, 当SQL语句结构不确定是, 只能使用${}实现.
@Test
public void test() {
SqlSession session = MyBatisUtil.getSession();
Map params = new HashMap<>();
params.put("tbName", "tb_user");
params.put("cname", "reg_time");
params.put("cvalue", "2019-12-24 15:18:35");
params.put("order", "order by id desc");
session.selectList("sel", params);
session.close();
}
增删改操作涉及到事务管理, MyBatis中, 默认将JDBC的自动管理事务机制关闭了. 要求所有增删改操作都必须进行手动的事务管理. 通过SqlSession来进行事务管理.
insert into tb_user values (
default, #{username}, #{password}, #{realName}, #{age}, #{birthday}, now()
)
@Test
public void testInsert() {
SqlSession session = MyBatisUtil.getSession();
User user = new User(20, "zhaomin3", "123", "赵敏", new Date());
// 新增前打印user对象
System.out.println(user);
int rows = session.insert("ins", user);
if(rows == 1) {
// 提交事务
session.commit();
System.out.println("ok");
} else {
System.out.println("error");
}
// 新增后打印user对象
System.out.println(user);
session.close();
}
update tb_user set username=#{uname}, real_name=#{rname} where id=#{id}
@Test
public void testUpdate() {
SqlSession session = MyBatisUtil.getSession();
Map params = new HashMap<>();
params.put("uname", "xiexun");
params.put("rname", "谢逊");
params.put("id", 9);
try {
session.update("upd", params);
session.commit();
} catch (Exception e) {
session.rollback();
e.printStackTrace();
}
session.close();
}
delete from tb_user where id=#{id}
@Test
public void testDelete() {
SqlSession session = MyBatisUtil.getSession();
session.delete("del", 8);
session.commit();
session.close();
}
主要针对映射文件中定位类型时使用, 简化配置. 分为两种情况:
这是一些为常见的 Java 类型内建的相应的类型别名。它们都是不区分大小写的,注意对基本类型名称重复采取的特殊命名风格。
别名 |
映射的类型 |
别名 |
映射的类型 |
别名 |
映射的类型 |
---|---|---|---|---|---|
_byte |
byte |
string |
String |
decimal |
BigDecimal |
_long |
long |
byte |
Byte |
bigdecimal |
BigDecimal |
_short |
short |
long |
Long |
object |
Object |
_int |
int |
short |
Short |
map |
Map |
_integer |
int |
int |
Integer |
hashmap |
HashMap |
_double |
double |
integer |
Integer |
list |
List |
_float |
float |
double |
Double |
arraylist |
ArrayList |
_boolean |
boolean |
float |
Float |
collection |
Collection |
|
|
boolean |
Boolean |
iterator |
Iterator |
|
|
date |
Date |
|
|
MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态SQL这一特性可以彻底摆脱这种痛苦。
用于条件判断, test属性表示判断结果, 要求是一个boolean值.
用于维护where子句, 通常配合
功能类似于java中的switch...case...default. 多分支判断, 只能成立一个条件.
对数据进行加工, 通常用于处理模糊查询的数据.
提取SQL片段和引用SQL片段
select id, username, password, real_name,
age, birthday, reg_time from tb_user
用于维护更新语句中的set子句, 类似于
update tb_user
id = #{id},
username=#{username},
password=#{password},
age=#{age},
where id=#{id}
对数组, List, Set, Map集合进行遍历时使用, 通常用于in操作中. 一般用于实现批量新增或批量删除操作. 属性介绍:
delete from tb_user where id in
#{id}
@Test
public void testForeach() {
SqlSession session = MyBatisUtil.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
// int[] ids = {1, 2, 3, 4, 5, 6};
// List ids = new ArrayList<>();
// Set ids = new HashSet<>();
// Collections.addAll(ids, 1, 3, 5, 7);
Map ids = new HashMap<>();
ids.put(1, 11);
ids.put(2, 22);
ids.put(3, 33);
mapper.delUser(ids);
session.close();
}
用于对数据进行处理, 可以在指定的字符串前后进行操作.
insert into tb_user values
,default, #{u.username}, #{u.password}, #{u.realName},
#{u.age}, #{u.birthday}, now(),
默认情况下, MyBatis会进行自动映射(Auto-Mapping), 数据库表格的列名和对象的属性名如果同名, MyBatis会进行自动赋值. 当列名和属性名不同., MyBatis允许程序员自己定义列名和属性名的映射关系.
如果使用了resultType属性, 表示自动映射, 如果使用了resultMap属性, 表示手动映射.
在MyBatis中, 多表连接查询主要分为两种, 一种是多对一, 一种是一对多.
create table tb_class (
id integer primary key auto_increment,
name varchar(10) not null,
room varchar(10)
);
# 创建学生表
create table tb_student (
id integer primary key auto_increment,
name varchar(20) not null,
gender char(1),
birthday date,
cid integer
);
# 添加数据
insert into tb_class values
(default, 'Java', '1601'),
(default, '计算机网络', '1602'),
(default, '数据结构', '1601');
insert into tb_student values
(default, '张三', '男', '1998-12-12', 1),
(default, '李四', '女', '1999-12-12', 2),
(default, '王五', '男', '1998-12-12', 2),
(default, '赵六', '男', '1998-12-12', 3),
(default, '孙七', '女', '1998-12-12', 3),
(default, '吴八', '女', '1998-12-12', 3);
多个学生对应一个班级, 查询所有学生信息, 同时查询每个学生所在班级的信息
8.1.1 实体类
在学生实体类中, 应该提供一个班级类型的对象, 用来表示班级信息.
public class Student implements Serializable {
private Integer id;
private String name, gender;
private Date birthday;
private Integer cid;
private Clazz clazz;
}
8.1.2 关联方式实现查询
指的是通过SQL语句关联查询的方式实现. 表1 joint 表2 on 关联条件.
在MyBatis中, 关联单个对象需要使用
8.1.3 N+1方式实现
指的是完成本次查询一共需要执行N+1条SQL语句. 每条SQL都是单表查询.
指的是一个班级有多个学生, 查询班级时把当前班级的所有学生也查到.
8.2.1 实体类
public class Clazz implements Serializable {
private Integer id;
private String name, room;
private List list = new ArrayList<>();
}
8.2.2 关联方式实现
8.2.3 N+1方式实现
MyBatis中常用的注解,使用MyBatis中的注解, 可以简化映射文件的配置. 注意, 动态SQL不能简化.
public interface DemoMapper {
@Select("select * from tb_user")
List selAll();
@Delete("delete from tb_user where id=#{id}")
void delById(int id);
}
注解模式使用注意事项
1使用注解的接口可以同时存在mapper映射文件
2接口上使用了注解 在映射文件中就不能在定义对应的SQL语句标签
3使用了注解的接口 接口中并不是所有的方法都必须使用注解 个别方法使用映射文件OK
注解模式开发的好处
简化mapper映射文件
注解模式开发的缺点
将SQL语句转移到了代码中 修改代码需要重新编译项目 耦合度高
没有办法独立处理一对一 一对多 多对多的关联关系
什么情况下使用注解开发?
1业务逻辑简单
2业务逻辑稳定