Mybatis是一个Apache下的开源项目,后来转到谷歌旗下 2013年迁移到GitHub上
是一个超轻量级的半自动ORM框架
其核心是
输入映射
将参数映射到sql语句中(JDBC中的参数替换)
输入映射支持的类型 八大基础数据类型 list map POJO 包装类型
包装类型可以直接通过对象导航的方式不断往下获取
例如:#{user.name}
输出映射 (JDBC ResultSet到对象的映射)
输出映射支持的类型 八大基础数据类型 list map POJO
输出包装类型时 需要自动映射字段
Mybatis帮我们管理事务,开发人员只需要关注具体sql语句即可(sql语句需要自己写 半自动)
Mybatis与hibernate
1.Mybatis需要手写sql 适用于需求变化频繁场景
2.切换数据库成本较高 通常需要重写一遍sql语句
3.不是一个完全的ORM映射 无法实现面向对象操作数据库
4.体积更小 学习难度更低
1.hibernate与数据库的关联性几乎没有 随时可以切换方言
2.更加完整的ORM映射 可以不编写sql语句
3.可以自动生成表结构 从实体类映射关联关系
4.体积大 学习过程更长
1.下载jar包
2.添加jar到工程中
mybatis核心包 依赖lib中的依赖包 连接数据库包
3.编写核心配置文件
没有命名规范
配置数据源的db.properties
4.编写Mapper文件
创建对应的数据库和表
添加主配置文件到mapper中
5.获取session进行操作
6.关闭资源
核心配置文件SqlMapConfig.xml
<configuration>
<properties resource="db.properties">properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/lanou/bean/User.xml"/>
<mapper resource="com/lanou/dao/UserDao.xml"/>
<mapper resource="com/lanou/dao/DogDao.xml"/>
<mapper class="com.lanou.dao.UserDao"/>
mappers>
configuration>
映射文件
<mapper namespace="test">
<select id="findUserById" parameterType="Integer" resultType="com.lanou.bean.User">
select * from user where id=#{id}
select>
<select id="searchByName" parameterType="String" resultType="com.lanou.bean.User">
select * from user where name like "%"#{value}"%"
select>
<insert id="add" parameterType="com.lanou.bean.User">
insert into user values(null,#{name},#{address},#{sex},#{phone},#{age})
insert>
<insert id="insertNewUser" parameterType="com.lanou.bean.User" useGeneratedKeys="true" keyProperty="id">
insert into user values(null,#{name},#{address},#{sex},#{phone},#{age})
insert>
mapper>
获取session进行操作
// 构建器
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 读取配置文件
InputStream input = Resources.getResourceAsStream("SqlMapConfig.xml");
// 获取会话工厂
SqlSessionFactory factory = builder.build(input);
// 获取会话
SqlSession session = factory.openSession();
// CRUD 注意 除了查询操作 都需要提交事务 因为默认是不自动提交
在传统分层结构中 有大量的dao层实现类 随着项目的扩展 这些类文件会越来越多 不方便维护
Mybatis提供了一种dao层的解决方案
纯接口开发
只有接口 没有实现类 Mybatis自动为接口生成代理对象 完成实现类的封装
实现原理:
生成代理对象 实现目标接口 并在代理对象中
通过mapper读取配置信息 生成相应的实现代码
之前手动创建实现类,手动调用mapper中定义好的sql语句
之后Mybatis根据接口创建实现类 在实现类中自动调用mapper中定义好的sql语句
具体操作
1.创建接口 定义需要的方法
public interface UserDao {
public User selectUserById(int id);
}
2.创建 编写映射文件mapper
<mapper namespace="com.lanou.dao.UserDao">
<select id="selectUserById" parameterType="int" resultType="com.lanou.bean.User">
select * from User where id = #{id}
select>
mapper>
3.把映射文件注册到主配置文件
<mapper resource="com/lanou/dao/UserDao.xml"/>
4.通过session获取接口实现对象
// 获取代理对象
UserDao dao = session.getMapper(UserDao.class);
User user = dao.selectUserById(1);
System.out.println(user);
加载配置文件发现有个UserDao.xml需要映射 创建UserDao等实现类
UserDao dao = new UserDao() {
@Override
public User selectUserById(int id) {
// 内部其实调用mapper定义的sql方法
return session.selectOne("com.lanou.dao.UserDao.selectUserById", id);
}
};
System.out.println(dao.selectUserById(5));
当我们传的参数是一个数组时
java中没有对应包装类型
可以写Object 也可以不写
parameterType作用其实是用来规范书写 怕你传错类型
遍历数组时参数名字是固定的 array
遍历list时参数名字固定是list
Mybatis参数映射的原理
其实是把你传过来的参数 转成map 以键值对的方式传递
常用标签
if 条件判断
where 拼接多个参数 会自动去除第一个and
foreach 遍历集合
sql 定义sql片段
include 配合sql一起使用
如果有很多sql重复 没有必要每次写 可以进行抽取
"selectUser">
select * from user
根据姓名和性别
<select id="getUser" parameterType="User" resultType="User">
<include refid="selectUser"/>
<where>
<if test="name != null and name != ''">
and name=#{name}
if>
<if test="sex != null and sex != ''">
and sex=#{sex}
if>
where>
select>
根据一堆id查询
<select id="selectUserByIds" parameterType="java.util.List" resultType="User">
<include refid="selectUser"/> where
id in
<foreach collection="list" item="item" separator="," open="(" close=")">
#{item}
foreach>
select>
orders表和user表 一个订单只有一个用户 从订单角度出发 是一对一关系
实现获取订单时 自动获取user
1.Orders类中声明User类型属性
private User user;
2.在接口中声明对应的查询方法
public interface OrdersDao {
public List getOrders();
}
3.在mapper中实现sql语句
4.手动映射列名到属性名
<resultMap type="Orders" id="OrdersMap" autoMapping="true">
<result property="name" column="o_name"/>
<result property="id" column="o_id"/>
<association property="user" autoMapping="true" javaType="User">
<result property="name" column="u_name"/>
<result property="id" column="u_id"/>
association>
resultMap>
一个用户有多个订单 从用户角度出发 是一对多关系
实现在查询user数据时 自动查询出对应的Orders数据
1.User类中声list类型属性
private List orders;
2.在接口中声明对应的查询方法
public List getUsers();
3.在mapper中实现sql语句
4.手动映射列名到属性名
"User" id="UserMap" autoMapping="true">
<result property="name" column="u_name"/>
<result property="id" column="u_id"/>
property="orders" ofType="Orders" autoMapping="true">
<result property="name" column="o_name"/>
<result property="id" column="o_id"/>
总结
手动映射的时候 AutoMapping 设为true 可以自动将列名与属性名对应数据映射
一对一 javaType用来指定关联对象的类型 必须写 否则空指针异常
一对多 ofType用来指定集合内元素的类型 必须写 否则空指针异常
现有 groups 和 user
需求 查询user 同时查询相关的groups
需求 查询groups 同时查询相关的user
多对多是一对多的特例(两个多对一) Mybatis中实现方式与一对多一样
唯一的区别是 sql语句不同 需要查三个表(中间表)