Mybatis 是我们常用的持久层框架之一,是我们熟悉的SSM中的“M”。
Mybatis 提供了灵活的数据库编程实现方式,提供了规范的数据库编程管理。相比古老的纯JDBC实现方式,也简化了数据库编程。
同时,由于SSM一直是经典,Mybatis的使用也成为程序员学习或工作中必不可少的环节。
在学习 Mybatis 之前,我们需要掌握一定的SQL基础,Spring、SpringMVC的一些基本用法。
本文的 Mybatis 代码演示需要结合Spring项目进行测试,因此需要读者先自行创建Spring项目并根据实际情况自行控制各依赖版本。
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.2.2version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<scope>runtimescope>
dependency>
以下配置读者参考时要注意将数据库名、用户名和密码替换成自己实际的名或密码。
使用 application.properties 的同学可参考如下配置:
spring.datasource.url=jdbc:mysql://localhost:3306/DatabaseName?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root
mybatis.mapper-locations=classpath:mapper/*.xml
使用 application.yml 的同学可参考如下配置:
mybatis:
type-aliases-package: cn.sharry.pojo.product.entity
mapper-locations: classpath:mybatis/mapper/*.xml
#mybatis缓存
configuration:
cache-enabled: true
如果读者使用的是传统的SSM实现方式,可能还需要使用mybatis.config.xml的配置方式,例如:
DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true" />
settings>
<typeAliases>
<typeAlias alias="Integer" type="java.lang.Integer" />
<typeAlias alias="Long" type="java.lang.Long" />
<typeAlias alias="HashMap" type="java.util.HashMap" />
<typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap" />
<typeAlias alias="ArrayList" type="java.util.ArrayList" />
<typeAlias alias="LinkedList" type="java.util.LinkedList" />
typeAliases>
configuration>
现在,由于有了SpringBoot 约定大于配置的特性,我们已逐步摒弃使用xml配置mybatis的方式。这种相对老式的配置可能还需要指定Mapper映射文件、高级数据库驱动等等,
这里先留个坑,若读者遇到这种老式项目的情况,可依情况再去查询。
mybatis需要明确哪些接口是需要生成代理对象,在一些小Demo或小项目中,我们常在接口上添加@Mapper注解。但当接口较多时,为了提高效率,我们可以使用配置类来指定扫描
的接口所在的包:
/**MapperScan("路径")*/
@Configuration
@MapperScan("cn.sharry.astore.product.mapper")
public class MybatisConfiguration {
}
配置完成后,我们可以在测试类进行配置结果的测试:
@SpringBootTest
class ApplicationTests {
@Test
void contextLoads() {
}
@Autowired
DataSource dataSource;
/**
* 测试数据源是否能正常连接
* @throws SQLException
*/
@Test
void testGetConnection() throws SQLException {
dataSource.getConnection();
}
}
在配置好mybatis后,我们通常有两种方式进行数据库编程:通过注解以及mapper.xml文件写sql。
举个例子,如果我们需要在某个Mapper执行插入操作,可以:
@Insert("insert into category values(null,#{name})")
void insert(String name);
其余标签@Select 、@Update、@Delete 用法与@Insert标签一致:
@[标签名]("[具体SQL语句]")
但是,由于实际开发中,一般表字段比较多,执行一些操作时sql语句可能会比较长,而且这种注解的方式不利于DBA的工作,因此我们一般比较少用注解的方式来进行数据库编程,此处对于这种实现方式的介绍也比较少,读者要有所侧重。
这是我们在学习、实际开发中用到更多的sql实现方式,需要在Mapper.xml中写SQL,例如:
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.sharry.mapper.UserMenuMapper">
<resultMap id="userMenus" type="cn.sharry.domain.SysUserMenu">
<id property="id" column="uid">id>
<result property="name" column="username">result>
<collection property="menus" ofType="cn.sharry.domain.SysMenu" autoMapping="true">
<id property="id" column="id">id>
collection>
resultMap>
<select id="findUserMenusById" resultMap="userMenus">
SELECT su.id uid, su.username username ,sm.*
FROM sys_users su
INNER JOIN sys_user_roles sur
ON su.id = sur.user_id
INNER JOIN sys_roles sr
ON sur.role_id = sr.id
INNER JOIN sys_role_menus srm
ON sr.id = srm.role_id
INNER JOIN sys_menus sm
ON srm.menu_id = sm.id
WHERE su.id = #{id}
select>
mapper>
这里提供一个空的Mapper.xml文件供读者使用:
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="">
mapper>
当然,读者也可以通过官网等途径获取。
我们通过基本的单表增删查改来对Mybatis进行一个基本的入门,然后见简单介绍分页、连表供读者参考。
这里我们直接通过mapper.xml的举例来说明,至于所涉及的具体表、Controller、Service 等,篇幅有限,读者需自行创建并参考例子测试。
假设我们需要插入一个album相册的数据:
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
INSERT INTO album (name, description, sort)
VALUES (#{name}, #{description}, #{sort})
insert>
useGeneratedKeys:允许JDBC自动生成主键;
keyProperty:指定主键
假设我们需要在album相册中根据id删除:
<delete id="deleteUserByIds">
DELETE FROM album
WHERE id in(
<foreach item="id" collection="array" open="("
close=")" separator=",">
#{id}
foreach>
)
delete>
foreach标签里包裹的是id数组,表示对id数组进行遍历
假设我们要查询 sys_users的列表:
<sql id="selectUser">
select id,username,password,salt,email,mobile,valid,deptId,createdTime,modifiedTime,createdUser,modifiedUser from sys_users
sql>
<select id="findUserList" resultType="cn.sharry.domain.SysUser">
<include refid="selectUser"/>
<where>
<if test="username != null and username != ''">
and username = #{username}
if>
where>
select>
sql标签:可存放sql片段,多用于可复用的语句;
where标签:去掉多余的and;
假设我们要修改album相册:
<update id="updateById">
UPDATE album
<set>
<if test="name != null">
name = #{name},
if>
<if test="description != null">
description = #{description},
if>
<if test=" sort != null">
sort = #{sort}
if>
set>
WHERE id = #{id}
update>
通过前面单表的增删查改后,这里再简单介绍一下分页查询与连表查询,均以例子体现:
<select id="listPage" resultMap="ListItemResultMap">
SELECT
<include refid="ListItemQueryFields" />
FROM
brand
ORDER BY id
LIMIT #{offset}, #{count}
select>
连表查询也是我们日常开发常用的,这里举个例子:
<resultMap id="userMenus" type="cn.sharry.domain.SysUserMenu">
<id property="id" column="uid">id>
<result property="name" column="username">result>
<collection property="menus" ofType="cn.sharry.domain.SysMenu" autoMapping="true">
<id property="id" column="id">id>
collection>
resultMap>
<select id="findUserMenusById" resultMap="userMenus">
SELECT su.id uid, su.username username ,sm.*
FROM sys_users su
INNER JOIN sys_user_roles sur
ON su.id = sur.user_id
INNER JOIN sys_roles sr
ON sur.role_id = sr.id
INNER JOIN sys_role_menus srm
ON sr.id = srm.role_id
INNER JOIN sys_menus sm
ON srm.menu_id = sm.id
WHERE su.id = #{id}
select>
通过上述列举的例子与简单说明,相信读者已基本了解了Mybatis如何使用。
本小节主要介绍一些使用Mybatis时的常见注意事项。
一般情况下,能用#{} 就用#{} !
#{} | ${} |
---|---|
预编译,默认为数据添加双引号,防止sql注入 | 当以字段名称为参数时才使用,一般不用 |
我们执行查询时,通常结果会有两种:resultType 与 resultMap
使用resultType: 通常查询数量、或者表字段名与实体类字段名相同时,可直接使用resultType,例如:
<!--根据名称查询相册数量-->
<select id="selectCountByName" resultType="int">
SELECT count(*)
FROM album
WHERE name = #{name}
</select>
使用resultMap: 通常表字段中带有下划线_时,因为实体类字段默认需要驼峰命名,需要用resultMap来对字段进行指定,例如:
<!--查询品牌列表,具体查询语句略-->
<select id="selectList" resultMap="ListResultMap">
SELECT
<include refid="StandardQueryFields"/>
FROM pms_brand
ORDER BY
sort DESC ,id
</select>
<resultMap id="ListResultMap" type="cn.sharry.product.pojo.vo.BrandListItemVO">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<result column="product_count" property="productCount"></result>
<result column="comment_count" property="commentCount"></result>
<result column="positive_comment_count" property="positiveCommentCount"></result>
</resultMap>
简单来说就是当实体类字段与数据库表字段不一致时就用resultMap
字符 | 相当于 |
---|---|
> | > 大于 |
< | < 小于 |
& | & 号 |
Mybatis 默认开启一级缓存,在同一个SqlSession对象中查询相同的数据,可以实现数据的共享。
二级缓存:默认开启,需要手动标识使用,在SqlSessionFactory中共享数据,标识方式:
只需要在sql映射文件中添加,例如:
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xxxxx">
<cache/>
....
mapper>
Mybatis是目前常用的优秀的持久层框架,基于ORM,以对象的方式操作数据库。使用Mybatis通常需要先进行配置,再根据具体业务编写xml映射文件。基本的增删查改实现方式大多相对固定;分页、连表、模糊查询等查询也常用,读者应稍加练习。最后就是需要注意一下一些传参注意事项、标签的作用、缓存等。至于完整地实现一个项目的MVC,可能需要配合Controller、Service等,篇幅有限,这里不赘述。
我们下一篇见!