【SSM框架系列】Mybatis映射配置文件与核心配置文件深入

传统开发方式Dao层实现

编写UserDao接口

    public interface UserDao {
        List<User> findAll() throws IOException;
    }

编写UserDaoImpl实现

    public class UserDaoImpl implements UserDao {
        public List<User> findAll() throws IOException {
            InputStream resourceAsStream = 
                        Resources.getResourceAsStream("SqlMapConfig.xml");
            SqlSessionFactory sqlSessionFactory = new 
                        SqlSessionFactoryBuilder().build(resourceAsStream);
            SqlSession sqlSession = sqlSessionFactory.openSession();
            List<User> userList = sqlSession.selectList("userMapper.findAll");
            sqlSession.close();
            return userList;
        }
    }

测试

    @Test
    public void testTraditionDao() throws IOException {
        UserDao userDao = new UserDaoImpl();
        List<User> all = userDao.findAll();
        System.out.println(all);
    }
    

Mybatis代理开发方式介绍

Mapper 接口开发方法只需要程序员编写Mapper 接口(相当于Dao 接口),由Mybatis 框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。

Mapper 接口开发需要遵循以下规范:

  1. Mapper.xml文件中的namespace与mapper接口的全限定名相同

  2. Mapper接口方法名和Mapper.xml中定义的每个statement的id相同

  3. Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同

  4. Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

分析:
映射配置文件中的namespace为什么要和接口的全限定类名一样?

  • 在加载核心配置文件时,可以获取映射配置文件,Mybatis就会去加载映射配置文件,解析里面的namespace和每个Statement,将解析到结果保存到一个Map中,Map的key是namespace + id,Map的Value是Mapper对象(SQL,结果集)
  • 在使用代理对象去调用接口方法时,Mybatis可以使用反射区拿到该调用方法的名称和当前类的全限定类名,然后将全限定类名 + 方法名称,组成一个Key,再去Map中查询对应的Key
  • 如果有就可以找到对应的Value,而Value中就有要执行的SQL和封装的结果集
  • 所以namespace必须和接口的全限定类名一致,id必须和接口中的方法名称一致

MyBatis映射文件深入

获取主键自增id

	<insert id="addUser" parameterType="user">
		<!--
			selectKey 标签可以用来获取新插入数据的主键
			keyProperty属性是指实体类中主键的属性名称
			keyColumn属性是指表中主键的字段名称
			resultType属性是指主键的数据类型
			order是指获取主键的函数是在插入语句之前执行还是之后执行
					AFTER表示之后,用于主键自增长
					BEFORE表示之前,用于主键非自增长
			select last_insert_id():得到刚 insert 进去记录的主键值,只适用与自增主键
		-->
        <selectKey resultType="int" keyProperty="id" keyColumn="id" order="AFTER">
            select last_insert_id()
        </selectKey>
        INSERT into t_user VALUES (#{id},#{username},#{password})
    </insert>

结果集Map封装

	<!--
			resultMap 标签可以用来描述实体类中的属性和表中字段的对应关系
			id属性是resultMap的标志,要求在同一个映射文件中唯一
			type属性是用来指定这个resultMap 要描述的实体对象是谁
		-->
	<resultMap id="xxoo" type="user">
		<!--
			<id>标签是用来描述主键的对应关系
			<result>标签是用来描述非主键的对应关系
			property属性是用来指定实体中的属性名称
			column属性是用来指定表中的字段名称
		-->
        <id property="id" column="id"></id>
        <result property="name" column="username"></result>
        <result property="password" column="password"></result>
    </resultMap>

动态 SQL 之 - if

根据实体类的不同取值,使用不同的 SQL语句来进行查询。比如在 id如果不为空时可以根据id查询,如果username 不同空时还要加入用户名作为条件。这种情况在我们的多条件组合查询中经常会碰到。

    <select id="findByCondition" parameterType="user" resultType="user">
        select * from User
        <!--
			where标签可以自动处理and
				如果有条件满足,会自动删除第一个and
				如果都不满足,where条件就不会出现
		-->
        <where>
        	<!--
				test中的表达式:
					如果有实体类中的属性,可以直接写,不要加#{}或者${}
					而且注意大小写,必须和实体类中的属性名称一致
			-->
            <if test="id!=0">
                and id=#{id}
            </if>
            <if test="username!=null">
                and username=#{username}
            </if>
        </where>
    </select>

动态 SQL 之 - foreach

循环执行sql的拼接操作,例如:SELECT * FROM USER WHERE id IN (1,2,5)。

    <select id="findByIds" parameterType="list" resultType="user">
        select * from User
        <where>
        	<!--
				foreach 标签是用来遍历的
				collection属性是指定要遍历的类型
				open属性是sql语句拼接的开始
				close属性是sql语句拼接的结束
				item属性是遍历的每个元素
				separator属性是连接多个元素的分隔符
				#{item的名称}:取值
			-->
            <foreach collection="array" open="id in(" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </where>
    </select>

<update id="xxxxx" parameterType="user">
        update usero 
        <set> 
        	<!--
				如果满足条件,set标签可以去除最后一个逗号
			-->
        	<if test="username!= null">
                username=#{username},
            </if>
            <if test="password!= null">
                password=#{password},
            </if> 
         <set>
         where id=#{id}
    </update>

SQL片段抽取:Sql 中可将重复的 sql 提取出来,使用时用 include 标签引用即可,最终达到 sql 重用的目的

    <!--抽取sql片段简化编写-->
    <sql id="selectUser" select * from User</sql>
    <select id="findById" parameterType="int" resultType="user">
        <include refid="selectUser"></include> where id=#{id}
    </select>
    <select id="findByIds" parameterType="list" resultType="user">
        <include refid="selectUser"></include>
        <where>
            <foreach collection="array" open="id in(" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </where>
    </select>

MyBatis核心配置文件深入

typeHandlers标签:配置类型转换器

无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。下表描述了一些默认的类型处理器(截取部分)。
在这里插入图片描述
可以重写类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。具体做法为:实现 org.apache.ibatis.type.TypeHandler 接口, 或继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler, 然后可以选择性地将它映射到一个JDBC类型。

例如需求:一个Java中的Date数据类型,我想将之存到数据库的时候存成一个1970年至今的毫秒数,取出来时转换成java的Date,即java的Date与数据库的varchar毫秒值之间转换。

步骤:

  • 定义转换类继承类BaseTypeHandler

  • 覆盖4个未实现的方法,其中setNonNullParameter为java程序设置数据到数据库的回调方法,getNullableResult为查询时 mysql的字符串类型转换成 java的Type类型的方法

  • 在MyBatis核心配置文件中进行注册

代码如下:

    public class MyDateTypeHandler extends BaseTypeHandler<Date> {
        public void setNonNullParameter(PreparedStatement preparedStatement, int i, Date date, JdbcType type) {
            preparedStatement.setString(i,date.getTime()+"");
        }
        public Date getNullableResult(ResultSet resultSet, String s) throws SQLException {
            return new Date(resultSet.getLong(s));
        }
        public Date getNullableResult(ResultSet resultSet, int i) throws SQLException {
            return new Date(resultSet.getLong(i));
        }
        public Date getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
            return callableStatement.getDate(i);
        }
    }
    <!--注册类型自定义转换器-->
    <typeHandlers>
        <typeHandler handler="cs.wy.typeHandlers.MyDateTypeHandler"></typeHandler>
    </typeHandlers>
plugins标签:Mybatis的分页插件

MyBatis可以使用第三方的插件来对功能进行扩展,分页助手PageHelper是将分页的复杂操作进行封装,使用简单的方式即可获得分页的相关数据

导入通用PageHelper坐标

    <!-- 分页助手 -->
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper</artifactId>
        <version>3.7.5</version>
    </dependency>
    <dependency>
        <groupId>com.github.jsqlparser</groupId>
        <artifactId>jsqlparser</artifactId>
        <version>0.9.1</version>
    </dependency>

在mybatis核心配置文件中配置PageHelper插件

    <!-- 注意:分页助手的插件  配置在通用馆mapper之前 -->
    <plugin interceptor="com.github.pagehelper.PageHelper">
        <!-- 指定方言 -->
        <property name="dialect" value="mysql"/>
    </plugin>

分页代码实现

    @Test
    public void testPageHelper(){
        //设置分页参数
        // 第一个参数是开始的页码
        // 第二个参数是每页显示条数
        PageHelper.startPage(1,2);
    
        List<User> select = userMapper2.select(null);
        for(User user : select){
            System.out.println(user);
        }
        
        //其他分页的数据
	    PageInfo<User> pageInfo = new PageInfo<User>(select);
	    System.out.println("总条数:"+pageInfo.getTotal());
	    System.out.println("总页数:"+pageInfo.getPages());
	    System.out.println("当前页:"+pageInfo.getPageNum());
	    System.out.println("每页显示长度:"+pageInfo.getPageSize());
	    System.out.println("是否第一页:"+pageInfo.isIsFirstPage());
	    System.out.println("是否最后一页:"+pageInfo.isIsLastPage());
    }

MyBatis核心配置文件常用标签:

1、properties标签:该标签可以加载外部的properties文件

2、typeAliases标签:设置类型别名

3、environments标签:数据源环境配置标签

4、typeHandlers标签:配置自定义类型处理器

5、plugins标签:配置MyBatis的插件

发布了34 篇原创文章 · 获赞 14 · 访问量 1568

猜你喜欢

转载自blog.csdn.net/Wan_Yuan/article/details/104768704
今日推荐