MyBatis
MyBatis 是 一款优秀的持久层框架,属于 ORM 映射。前身是 ibatis。
MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 通过开发者书写 SQL 语句,以及对象模型和关系模型的映射(ORM),完成对象模型和关系模型的数据转换。同时支持延迟加载,缓存,映射等。
MyBatis 可以通过简单的 XML 或注释来配置和映射对象模型和关系模型,从而完成对象数据和关系数据的转换。
MyBatis 中文网:mybatis.net.cn/
MyBatis 组成:
核心对象: SqlSessionFactory SqlSession
配置文件:
mybatis.cfg.xml------------>主配置文件,用于配置数据源,链接各种 ORM 映射文件,以及实体类别名、日志等。
多个 ORM 映射文件----------->用于书写实体类和表的映射关系,操作数据库的 SQL 语句,以及配置持久接口。
MyBatis 环境搭建
导入依赖
<dependencies>
//驱动包
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>
//mybatis包
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-typehandlers-jsr310</artifactId>
<version>1.0.2</version>
</dependency>
</dependencies>
1、建立实体类
public class ProductBean {
/**编号*/
private Integer id;
/**商品名*/
private String name;
/**生产日期*/
private LocalDate createDate;
/**单价*/
private Integer price;
}
2、建立业务接口
public interface IProductService {
public void add(ProductBean product);
}
3、建立 mapper接口(相当于持久接口)
public interface IProductMapper {
public void add(ProductBean product);
public void del(Integer id);
public void update(Integer id,Integer price);
}
4、在 resources 目录中导入 mybatis.cfg.xml
<configuration>
<settings>
<!--日志-->
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
<typeAliases>
<!--给指定的类,加别名-->
<!-- <typeAlias type="com.project.bean.ProductBean" alias="product"></typeAlias>-->
<!--将指定包中的所有实体类,以实体类的类名,作为别名-->
<package name="com.project.bean"/>
</typeAliases>
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<!--配置驱动类-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!--配置URL,allowMultiQueries=true:表示允许一个语块中,书写多条SQL语句-->
<property name="url" value="jdbc:mysql://localhost:12345/mydb?characterEncoding=utf-8&allowMultiQueries=true"/>
<!--配置用户名-->
<property name="username" value="root"/>
<!--配置密码-->
<property name="password" value="lovo"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--加载指定包中所有的mapper文件,要求mapper文件名和接口名同名,
mapper文件名的命名空间必须和接口同名-->
<package name="com.project.mapper"/>
</mappers>
</configuration>
5、在 resources 目录中,创建包:com/project/mapper(必须和接口所在包同名),在包中导入 mapper配置文件。
<!--namespace 为命名空间,必须和mapper接口同名-->
<mapper namespace="com.project.mapper.IProductMapper">
<insert id="add"><!--添加语句块,id必须和接口方法同名-->
insert into t_product(p_name,p_createDate,p_price)
values(#{name},#{createDate},#{price});
</insert>
</mapper>
6、建立 service 父类 BaseService
public class BaseService {
private static SqlSessionFactory factory;
static {
try {
//从类路径中,加载主配置文件
Reader r = Resources.getResourceAsReader("mybatis.cfg.xml");
//创建会话工厂
factory = new SqlSessionFactoryBuilder().build(r);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 创建并返回sqlSession对象
* @return sqlSession对象
*/
public SqlSession getSession(){
return factory.openSession();
}
}
7、建立 service 接口实现类
public class ProductServiceImpl extends BaseService implements IProductService {
@Override
public void add(ProductBean product) {
//创建并得到会话对象
SqlSession session = this.getSession();
//创建并返回mapper接口对象
IProductMapper mapper = session.getMapper(IProductMapper.class);
mapper.add(product);
//提交事务
session.commit();
//关闭连接
session.close();
}
}
在开发中,有时候需要得到新加记录的编号,由于编号很多时候是自动增长列,由 DBMS 进行分配。所以,新加记录的编号,开发者是不清楚的。这时,可以在语句块添加属性 useGeneratedKeys,允许得到自动增长列的值,keyProperty 表示将自动增长列的值,填充实体对象的哪个属性。
<insert id="addProduct" useGeneratedKeys="true" keyProperty="id">
insert into t_product(p_name,p_createDate,p_price)
values (#{name},#{createDate},#{price});
</insert>
删除:
1、在 mapper 文件中,书写 语句块
<delete id="del">
delete from t_product where pk_productId=#{id};
</delete>
如果方法中,只有一个参数,并且该参数是简单类型(int,String),占位符名称可以随意。
2、书写 service 方法
public void del(Integer id) {
SqlSession session = this.getSession();
IProductMapper mapper = session.getMapper(IProductMapper.class);
mapper.del(id);
session.commit();
session.close();
}
修改:
1、如果 mapper 方法中,有多个参数,必须给参数加上别名。
public void update(@Param("pid") Integer id, @Param("price") Integer price);
2、在 mapper 文件中,书写 语句块
<update id="update">
update t_product set p_price=#{price} where pk_productId=#{pid};
</update>
3、书写 service 方法
public void update(Integer id, Integer price) {
SqlSession session = this.getSession();
IProductMapper mapper = session.getMapper(IProductMapper.class);
mapper.update(id,price);
session.commit();
session.close();
}
MyBatis 查询操作
在执行查询操作时,需要指定查询操作返回的结果。可以通过 resultType 和 resultMap 指定义。
resultType 用于指定返回的实体类型。可以是简单类型(int,String),可以是对象类型。当返回的是实体类型时,要求属性名和列名一致。否则无法根据列名封装对象的属性。
resultMap 用于定义属性和数据库列的对应关系,提高重用性,其他查询语句也可以引用。当列名和属性同名时可以不用写映射。
查询所有:
1、在 mapper 文件中,定义 resultMap映射
<resultMap id="productMap" type="ProductBean">
<id column="pk_productId" property="id"></id>
<result column="p_name" property="name"></result>
<result column="p_createDate" property="createDate"></result>
<result column="p_price" property="price"></result>
</resultMap>
2、在 mapper 文件中,书写查询 SQL
<select id="findAll" resultMap="productMap">
select * from t_product;
</select>
3、书写 service 方法
public List<ProductBean> findAll() {
SqlSession session = this.getSession();
IProductMapper mapper = session.getMapper(IProductMapper.class);
List<ProductBean> list = mapper.findAll();
session.close();
return list;
}
条件查询:
MyBatis 有两种占位符:# 和 $。
#:在生成 SQL 时,对于字符类型、日期类型参数,会拼装引号。
时容易引起 SQL 注入。
按姓名模糊查询:
1、在 mapper 文件中,书写查询 SQL
<select id="findByName" resultMap="productMap">
select * from t_product where p_name like "%"#{name}"%";
</select>
2、书写 service 方法
public List<ProductBean> findByName(String name) {
SqlSession session = this.getSession();
IProductMapper mapper = session.getMapper(IProductMapper.class);
List<ProductBean> list = mapper.findByName(name);
session.close();
return list;
}
动态条件分页查询:
1、建立业务接口
public CutPageBean<ProductBean> cutByItem(Integer pageNO ,
String name,
LocalDate startDate, LocalDate endDate);
2、建立 mapper 接口
public List<ProductBean> cutList(@Param("name") String name,
@Param("startDate") LocalDate startDate, @Param("endDate") LocalDate endDate,
@Param("startRow") Integer startRow, @Param("pageSize") Integer pageSize);
public int cutCount(@Param("name") String name,
@Param("startDate") LocalDate startDate,
@Param("endDate") LocalDate endDate);
3、在 mapper 文件中,书写 SQL 语句
如果一段 SQL 语句,可以用于多个语句块时,可以用 标签封装起来,便于重复利用。
<sql id="dynaSql">
<if test="name != null and name != '' ">
and p_name like "%"#{name}"%"
</if>
<if test="startDate != null">
and p_createDate >= #{startDate}
</if>
<if test="endDate != null">
<![CDATA[
and p_createDate <= #{endDate}
]]>
</if>
</sql>
if 标签条件为真时,表示拼接指定的 SQL 语句。由于在 XML 文件中有一些特殊字符,比如:>、<、& 等,这时可以用 包起来。这样无论里面是什么值都当字符串处理,不会因为有特殊符号,而导致编译报错。
引入 语句块,采用 标签
<select id="cutList" resultMap="productMap">
select * from t_product where 1=1
<include refid="dynaSql"></include>
limit #{startRow},#{pageSize};
</select>
<select id="cutCount" resultType="int">
select count(*) from t_product where 1=1
<include refid="dynaSql"></include>
</select>
4、书写业务方法
public CutPageBean<ProductBean> cutByItem(Integer pageNO, String name, LocalDate startDate, LocalDate endDate) {
SqlSession session = this.getSession();
IProductMapper mapper = session.getMapper(IProductMapper.class);
CutPageBean<ProductBean> cutBean = new CutPageBean<>();
cutBean.setList(mapper.cutList(name,startDate,endDate,(pageNO-1)*CutPageBean.PAGESIZE,CutPageBean.PAGESIZE));
cutBean.setCount(mapper.cutCount(name,startDate,endDate));
session.close();
return cutBean;
}
MyBatis 注解
使用 MyBatis 注解开发,可以在定义 mapper 接口时书写 SQL 语句。可以省去类配置文件,简洁方便。但是比较复杂的 SQL 和动态 SQL 还是建议属性类配置文件。