前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >17-MyBatis映射文件与核心配置文件深入

17-MyBatis映射文件与核心配置文件深入

作者头像
Ywrby
发布2022-10-27 13:15:41
4000
发布2022-10-27 13:15:41
举报
文章被收录于专栏:Ywrby

MyBatis映射文件深入

动态sql

可以看到,在之前的映射文件中,所有sql语句都是写死的,并不会根据我传入参数的不同进行区分,但在实际开发过程中,可能需要执行sql语句查询前先进行逻辑判断或其他操作,对参数进行简单的判断

例如下面的简单情况,我们在映射文件中写明了查询的条件,需要你User对象传入三个参数

代码语言:javascript
复制
<select id="findByCondition" parameterType="user" resultType="user">
    select * from user where id=#{id} and username=#{username} and  password=#{password}
</select>

此时,传入的User对象若存在该三个属性值则能够进行正常的查询

代码语言:javascript
复制
@Test
public void test() throws IOException {
    User user=new User();
    user.setId((long) 4);
    user.setUsername("lily");
    user.setPassword("1234");
    InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
    SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(resourceAsStream);
    SqlSession sqlSession = factory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<User> users = mapper.findByCondition(user);
    System.out.println(users);
}
/* 执行结果
[User{id=4, username='lily', password='1234'}]
*/

若我们传入的User没有任一属性值,则不能正确查询

代码语言:javascript
复制
@Test
public void test() throws IOException {
    User user=new User();
    user.setId((long) 4);
    //user.setUsername("lily");
    user.setPassword("1234");
    InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
    SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(resourceAsStream);
    SqlSession sqlSession = factory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<User> users = mapper.findByCondition(user);
    System.out.println(users);
}
/* 执行结果为[]
因为缺少属性值username所以查询语句变成了
select * from user where id=4 and username=null and  password=1234
而不存在username为空的数据,所以返回空集合
*/

很明显这不是我们想要达成的业务逻辑,所以我们可以采用动态sql的方式,通过提供的标签进行简单的逻辑判断

if标签

if标签用于进行判断逻辑操作,使用方式如下,分别判断各个属性值是否为空,若不为空则将对应语句添加到原语句的后面,若为空则不添加,这里的where标签与数据库中的where语法一致,只是它可以自动合理的帮我们拼接多个if条件语句,并且如果所有条件均不满足,where不会拼接

代码语言:javascript
复制
<select id="findByCondition" parameterType="user" resultType="user">
    select * from user
    <where>
        <if test="id!=0">
            and id=#{id}
        </if>
        <if test="username!=null">
            and username=#{username}
        </if>
        <if test="password!=null">
            and password=#{password}
        </if>
    </where>
</select>

使用后,原测试用例在省略参数后也可以正常查询到符合条件的数据

foreach标签

在实际应用中,我们还可能遇到查询条件不唯一的情况,例如所有编号为1或2或3的查询结果,如果单纯利用sql语句的方式可以写为SELECT * FROM user WHERE id IN (1,2,3),而实际开发中这个list集合一般是由service层传递给mapper层作为参数进行查询,此时就需要用到foreach标签进行集合的遍历

foreach标签的属性值较多,其分别代表:

collection:集合类型,可以为list或array

item:表示遍历的元素的名称

open:语句开头的内容,根据sql语句进行填写

close:语句结束的部分,同样根据sql语句进行填写即可

separator:元素之间的分隔符,分割每个遍历元素的

标签体中写元素格式即可

代码语言:javascript
复制
<select id="findByList" parameterType="list" resultType="user">
    select * from user
    <where>
        <foreach collection="list" item="id" open="id in (" close=")" separator=",">
            #{id}
        </foreach>
    </where>
</select>

foreach标签的拼接结果是id IN (1,2,3) 再利用where标签将其与原语句拼接后得到SELECT * FROM user WHERE id IN (1,2,3)

sql片段的抽取

对于配置文件中高度重复的sql语句片段,我们可以利用抽取的思想对语句片段进行抽取,方便复用和修改

代码语言:javascript
复制
<!--sql语句的抽取-->
<sql id="selectAll">select * from user</sql>

<!--使用抽取的sql语句-->
<select id="findByList" parameterType="list" resultType="user">
    <include refid="selectAll"></include>
    <where>
        <foreach collection="list" item="id" open="id in (" close=")" separator=",">
            #{id}
        </foreach>
    </where>
</select>

MyBatis核心配置文件深入

typeHandler-类型转换器

当我们从数据库获取数据或将数据写入数据库的过程中,始终存在类型转换的过程,例如Java中的Integer到数据库中的int或Java中的String到数据库中的varchar,这些基本数据类型的转换MyBatis已经有自己默认的类型转换器,一般情况下不需要我们处理,但当我们要处理自己定义的类型或MyBaitis没有默认处理的类型时,就需要自己定义类型转换器(例如将日期类型转换为毫秒值存入数据库,再在读取数据时将毫秒值转为日期)

typeHandler使用步骤

这里实现了将Date类型存入数据库的过程中转换为毫秒值传入,并在从数据库读取该数据时重新转换为Date类型存入User对象

1. 定义转换类继承类BaseTypeHandler并实现方法
代码语言:javascript
复制
public class DateTypeHandler extends BaseTypeHandler<Date> {
    //将Java类型转换为数据库所需的类型,参数i表示将转换后数据插入的位置,字段躲在的列
    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, Date date, JdbcType jdbcType) throws SQLException {
        //将日期转为长整型
        long time = date.getTime();
        //设置参数
        preparedStatement.setLong(i,time);
    }

    //将数据库类型转换为Java所需的类型
    //s参数表示数据表字段的名称,resultSet是查询结果集
    @Override
    public Date getNullableResult(ResultSet resultSet, String s) throws SQLException {
        //获取数据库中的数据
        Long dateTime=resultSet.getLong(s);
        //转化为Java中的Date类型
        Date date=new Date(dateTime);
        //返回数据
        return date;
    }

    //将数据库类型转换为Java所需的类型
    @Override
    public Date getNullableResult(ResultSet resultSet, int i) throws SQLException {
        //获取数据库中的数据
        Long dateTime=resultSet.getLong(i);
        //转化为Java中的Date类型
        Date date=new Date(dateTime);
        //返回数据
        return date;
    }

    //将数据库类型转换为Java所需的类型
    @Override
    public Date getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        //获取数据库中的数据
        Long dateTime=callableStatement.getLong(i);
        //转化为Java中的Date类型
        Date date=new Date(dateTime);
        //返回数据
        return date;
    }
}
2. 在MyBatis核心配置文件中配置转换器
代码语言:javascript
复制
<!--自定义类型转换器-->
<typeHandlers>
    <typeHandler handler="cn.ywrby.handler.DateTypeHandler"/>
</typeHandlers>
3. 测试转换效果
代码语言:javascript
复制
@Test
public void test() throws IOException {
    User user=new User();
    user.setId((long) 6);
    user.setUsername("Kelly");
    user.setPassword("1234");
    //获取当前时间并作为参数传入
    user.setDate(new Date());
    InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
    SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(resourceAsStream);
    SqlSession sqlSession = factory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    //测试能否将Date类型转为毫秒值保存到数据库
    mapper.save(user);
    sqlSession.commit();
    //测试从数据库读取数据能否正确转换为Java中的Date类型
    List<User> userList = mapper.findByCondition(user);
    System.out.println(userList);
    sqlSession.close();
}
/* 运行结果
[User{id=6, username='Kelly', password='1234', date=Sat Mar 20 16:30:36 CST 2021}]
 */

数据库显示效果

可以看到首先成功将Date类型存入数据库的值变为毫秒值,而从数据读取到Java过程中又转换回了Date类型

plugins-插件标签

MyBatis可以使用第三方插件来进行功能的扩展,这里以分页助手(page-helper)为例进行插件使用的演示,其功能是将复杂的分页技术进行封装,使用简单的方式即可获取分页数据

插件使用步骤

  1. 导入插件的坐标
  2. 在mybatis核心配置文件中配置插件
  3. 测试分页数据的获取
导入page-helper的坐标
代码语言:javascript
复制
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.3.3</version>
</dependency>
在核心配置文件中配置插件
代码语言:javascript
复制
<!--
plugins在配置文件中的位置必须符合要求,否则会报错,顺序如下:
properties?, settings?,
typeAliases?, typeHandlers?,
objectFactory?,objectWrapperFactory?,
plugins?,
environments?, databaseIdProvider?, mappers?
-->
<plugins>
    <!-- com.github.pagehelper为PageHelper类所在包名 -->
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        <!--配置数据库方言-->
        <property name="helperDialect" value="mysql"/>
    </plugin>
</plugins>
测试分页数据获取
代码语言:javascript
复制
@Test
public void test() throws IOException {
    InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
    SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(resourceAsStream);
    SqlSession sqlSession = factory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    //设置分页相关参数 当前页,每页显示的条数
    PageHelper.startPage(1,3);

    List<User> userList=mapper.findAll();
    for (User user:userList){
        System.out.println(user);
    }

    //获得与分页相关的参数
    PageInfo<User> pageInfo=new PageInfo<User>(userList);
    //输出相关信息
    System.out.println("当前页:"+pageInfo.getPageNum());
    System.out.println("总条数:"+pageInfo.getTotal());
    System.out.println("总页数:"+pageInfo.getPages());
    System.out.println("上一页:"+pageInfo.getPrePage());

    sqlSession.close();
}
/* 运行结果
User{id=1, username='Leslie', password='123', date=null}
User{id=2, username='Jessica', password='123', date=null}
User{id=4, username='lily', password='1234', date=null}
当前页:1
总条数:6
总页数:2
上一页:0
 */

可以看到,数据按照指定的第一页显示三条进行了输出,并且可以通过PageInfo对象获取所有的分页信息

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-03-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • MyBatis映射文件深入
    • 动态sql
      • if标签
      • foreach标签
    • sql片段的抽取
    • MyBatis核心配置文件深入
      • typeHandler-类型转换器
        • typeHandler使用步骤
      • plugins-插件标签
        • 插件使用步骤
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档