SSM之Mybatis_ch3——XML映射文件细解(一)

SSM之Mybatis_ch3

XML映射文件细解(一)

  • cache——命名空间的缓存配置
  • cache-ref——引用其他命名空间的缓存配置
  • resultMap——从数据库结果集中加载对象,是最复杂也最强大的元素
  • sql——可被其他语句引用的可重用语句块
  • insert——映射插入语句
  • update——映射更新语句
  • delete——映射删除语句
  • select——映射查询语句

此篇只讲述select、insert、update、delete以及resultMap入门。

select

<select id="getUser" parameterType="int" resultType="com.reflect.pojo.User">
    select * from mybatis.user where id=#{id}
</select>
  • id为getUser(对应UserMapper接口中的方法名)
  • parameterType:参数类型。接收一个int(或Integer)类型的参数
  • resultType:查询出的结果集的类型

#{id} 类似于JDBC中的PreparedStatement中的"?"参数传递id

i d 在 M y B a t i s 中 也 有 ‘ {id} 在MyBatis中也有` id在MyBatis中也有‘{}`,但是无法保证安全性。不推荐使用

即#{id}能防止SQL注入,而${id}不能。

以下列出select常用的部分属性,其他可访问MyBatis官网进行参考。

属性 描述
id 在命名空间中唯一的标识符,可以被用来引用这条语句
parameterType 传入这条语句的参数的类全限定名或别名。此属性是可选的
resultType 从这条语句中返回结果的类全限定名或别名。如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型
resultMap 对外部 resultMap 的命名引用。resultType 和 resultMap 之间只能同时使用一个
flushCache 将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false
useCache 将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true
timeout 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)

insert, update 和 delete

三者十分相似,只是实现的功能不同。

(其实不管用insert/update/delete哪个标签都无所谓,主要是其中的sql语句起作用,但是一般遵从规则,才使得三者分别对应不同的sql语句来执行不同的功能)

<insert id="insertUser" parameterType="com.reflect.pojo.User">
    insert into mybatis.user (id,name,pwd) values (#{id},#{name},#{pwd})
</insert>

<update id="updateUser" parameterType="com.reflect.pojo.User">
    update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id}
</update>

<delete id="deleteUser" parameterType="com.reflect.pojo.User">
    delete from mybatis.user where id=#{id}
</delete>

以下列出三者常用的部分属性,其他可访问MyBatis官网进行参考。

属性 描述
id 在命名空间中唯一的标识符,可以被用来引用这条语句
parameterType 传入这条语句的参数的类全限定名或别名,此属性是可选的
flushCache 将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:(对 insert、update 和 delete 语句)true。
timeout 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)
useGeneratedKeys 仅适用于 insert 和 update)指定能够唯一识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset)。如果生成列不止一个,可以用逗号分隔多个属性名称。
keyColumn 仅适用于 insert 和 update)设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称。

插曲——分页

1、通过MySQL数据库的Limit关键字实现分页

<!--UserMapper.xml中-->
<!--分页1-->
<select id="getUserByLimit" parameterType="map" resultType="com.reflect.pojo.User">
    select * from mybatis.user limit #{startIndex},#{pageSize}
</select>
// 分页1:通过查询数据库进行分页,此处只是mysql的分页,其他数据库可能不支持
@Test
public void getUserByLimit() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    try {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        Map<String, Integer> map = new HashMap<>();
        map.put("startIndex",0);
        map.put("pageSize",2);
        List<User> userList = mapper.getUserByLimit(map);
        for (User user : userList) {
            System.out.println(user);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        sqlSession.close();
    }
}

最终运行结果:

SSM之Mybatis_ch3——XML映射文件细解(一)

2、通过Java代码实现分页

<!--UserMapper.xml中-->
<!--分页2-->
<select id="getUserByRowBounds" resultType="com.reflect.pojo.User">
    select * from mybatis.user;
</select>
// 分页2:通过Java代码层面进行分页
@Test
public void getUserByRowBounds() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    try {
        // RowBounds实现
        RowBounds rowBounds = new RowBounds(1,2);
        // 通过java代码实现分页
        List<User> userList = sqlSession.selectList("com.reflect.mapper.UserMapper.getUserByRowBounds",null,rowBounds);
        for (User user : userList) {
            System.out.println(user);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        sqlSession.close();
    }
}

最终运行结果:

SSM之Mybatis_ch3——XML映射文件细解(一)

插曲——日志的示例

<!--mybatis-config.xml中-->
<!--配置日志文件 建议从官网复制logImpl,可能会出错-->
<settings>
    <!--标准日志工厂实现-->
    <!--<setting name="logImpl" value="STDOUT_LOGGING"/>-->
    <setting name="logImpl" value="LOG4J"/>
</settings>

#log4j.properties

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file

#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold = DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = [%c]-%m%n

#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/reflect.log
log4j.appender.file.MaxFileSize = 10MB
log4j.appender.file.Threshold = DEBUG
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = [%p][ghost%d{yy-MM-dd}][%c]%m%n

#日志输出级别
log4j.logger.org.mybatis = DEBUG
log4j.logger.java.sql = DEBUG
log4j.logger.java.sql.Statement = DEBUG
log4j.logger.java.sql.ResultSet = DEBUG
log4j.logger.java.sql.PreparedStatement = DEBUG

之后的随意运行一个Test方法,将会在当前项目下新建一个log目录reflect.log,不断往其中追加内容。控制台也会打印出相关内容

SSM之Mybatis_ch3——XML映射文件细解(一)

resultMap

初步入门:

resultMap能很好地解决属性名与数据库中字段名不一致的情况。

一般情况下,可以使用如下取别名方式:

<!--数据库中字段一般有下划线,因为一般数据库字段名一般小写-->
<select id="selectUsers" resultType="User">
  select
    user_id             as "id",
    user_name           as "userName",
    hashed_password     as "hashedPassword"
  from some_table
  where id = #{id}
</select>

如上所示的select简单语句并没有显式配置结果映射,MyBatis会在幕后自动创建一个resultmap,再根据属性名来映射到pojo中的JavaBean中属性上。如下所示:

<resultMap id="userResultMap" type="User">
  <id property="id" column="user_id" />
  <result property="username" column="user_name"/>
  <result property="password" column="hashed_password"/>
</resultMap>

综合一下,实际上显示配置resultMap就是如下所示:

<!--此处的type应该为com.reflect.pojo.User,但已经在配置文件中将pojo包进行配置,
    故此处直接使用User,Mybatis将会在使用JavaBean时自动到pojo包下寻找-->
    <resultMap id="UserMap" type="User">
    <!--property对应实体类中的属性,column对应数据库中的字段名-->
	<!--当只有某些属性与字段不重名,只需要单独配置这些属性与字段的关系即可-->
    <result property="pwd" column="pwd"/>
    </resultMap>

    <select id="getUser" parameterType="int" resultMap="UserMap">
    select * from mybatis.user where id=#{id}
</select>

高级映射:

见第五篇文章

全部代码

项目结构图

SSM之Mybatis_ch3——XML映射文件细解(一)

1.新建User.java

package com.reflect.pojo;

import org.apache.ibatis.type.Alias;

/**
 * author: Administrator
 * date: 2020/12/30 - 22:56
 */
// 这是第三种取别名方式
@Alias("user")
public class User {
    private int id;
    private String name;
    private String pwd;

    public User() {
    }

    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}

2.新建UserMapper.java

package com.reflect.mapper;

import com.reflect.pojo.User;

import java.util.List;
import java.util.Map;

/**
 * author: Administrator
 * date: 2020/12/30 - 22:57
 */
public interface UserMapper {
    // 查询单个用户
    User getUser(int id);

    // 新增一个用户
    boolean insertUser(User user);

    // 修改一个用户
    boolean updateUser(User user);

    // 删除一个用户
    boolean deleteUser(int id);

    //分页1
    List<User> getUserByLimit(Map<String,Integer> map);

    //分页2
    List<User> getUserByRowBounds(Map<String,Integer> map);
}

3.新建Usermapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--namespace绑定一个对应的mapper接口-->
<mapper namespace="com.reflect.mapper.UserMapper">
<!--    <select id="getUser" parameterType="int" resultType="com.reflect.pojo.User">-->
<!--        select * from mybatis.user where id=#{id}-->
<!--    </select>-->

<!--    分页1-->
    <select id="getUserByLimit" parameterType="map" resultType="com.reflect.pojo.User">
        select * from mybatis.user limit #{startIndex},#{pageSize}
    </select>

<!--    分页2-->
    <select id="getUserByRowBounds" resultType="com.reflect.pojo.User">
        select * from mybatis.user;
    </select>

    <insert id="insertUser" parameterType="com.reflect.pojo.User">
        insert into mybatis.user (id,name,pwd) values (#{id},#{name},#{pwd})
    </insert>

    <update id="updateUser" parameterType="com.reflect.pojo.User">
        update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id}
    </update>

    <delete id="deleteUser" parameterType="com.reflect.pojo.User">
        delete from mybatis.user where id=#{id}
    </delete>

<!--    此处的type应该为com.reflect.pojo.User,但已经在配置文件中将pojo包进行配置,
        故此处直接使用User,Mybatis将会在使用JavaBean时自动到pojo包下寻找-->
    <resultMap id="UserMap" type="User">
<!--        property对应实体类中的属性,column对应数据库中的字段名-->
        <result property="pwd" column="pwd"/>
    </resultMap>

    <select id="getUser" parameterType="int" resultMap="UserMap">
        select * from mybatis.user where id=#{id}
    </select>
</mapper>

4.新建MybatisUtils.java

package com.reflect.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.InputStream;

/**
 * author: Administrator
 * date: 2020/12/30 - 22:52
 */
public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static SqlSession getSqlSession() {
        return sqlSessionFactory.openSession();
    }
}

5.新建mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <properties resource="dbconfig.properties">
    </properties>

    <!--配置日志文件 建议从官网复制logImpl,可能会出错-->
    <settings>
        <!--标准日志工厂实现-->
        <!--<setting name="logImpl" value="STDOUT_LOGGING"/>-->
        <setting name="logImpl" value="LOG4J"/>
    </settings>
    
    <typeAliases>
        <package name="com.reflect.pojo"/>
    </typeAliases>

    <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>

<!--    此处的resource要注意是'/',而不是'.'-->
    <mappers>
        <mapper resource="com/reflect/mapper/UserMapper.xml"/>
    </mappers>
</configuration>

6.新建dbconfig.properties

driver=com.mysql.cj.jdbc.Driver
#url中&在配置文件可以直接写,但是在程序中需要进行可能转义
url=jdbc:mysql://192.168.199.131:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8
username=root
password=123456

7.新建log4j.properties

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file

#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold = DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = [%c]-%m%n

#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/reflect.log
log4j.appender.file.MaxFileSize = 10MB
log4j.appender.file.Threshold = DEBUG
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = [%p][ghost%d{yy-MM-dd}][%c]%m%n

#日志输出级别
log4j.logger.org.mybatis = DEBUG
log4j.logger.java.sql = DEBUG
log4j.logger.java.sql.Statement = DEBUG
log4j.logger.java.sql.ResultSet = DEBUG
log4j.logger.java.sql.PreparedStatement = DEBUG

8.新建Test类进行测试

import com.reflect.mapper.UserMapper;
import com.reflect.pojo.User;
import com.reflect.utils.MybatisUtils;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * author: Administrator
 * date: 2020/12/30 - 23:01
 */
public class MyTest {

    // 查询单个用户
    @Test
    public void getUser() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        try {
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            User user = mapper.getUser(1);
            System.out.println(user);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
    }

    // 分页1:通过查询数据库进行分页,此处只是mysql的分页,其他数据库可能不支持
    @Test
    public void getUserByLimit() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try {
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            Map<String, Integer> map = new HashMap<>();
            map.put("startIndex",0);
            map.put("pageSize",2);
            List<User> userList = mapper.getUserByLimit(map);
            for (User user : userList) {
                System.out.println(user);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
    }

    // 分页2:通过Java代码层面进行分页
    @Test
    public void getUserByRowBounds() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try {
            // RowBounds实现
            RowBounds rowBounds = new RowBounds(0,2);
            // 通过java代码实现分页
            List<User> userList = sqlSession.selectList("com.reflect.mapper.UserMapper.getUserByRowBounds",null,rowBounds);
            for (User user : userList) {
                System.out.println(user);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
    }

    // 新增一个用户
    @Test
    public void insertUser() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        int id = (int) (Math.random()*1000000000);
        String string = UUID.randomUUID().toString();

        try {
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            boolean res = mapper.insertUser(new User(id, string, "pwd"+string));
            if (res) {
                System.out.println("插入成功!!!");
            }
            // 提交事务(即使打印出成功结果,不提交也是不会插入数据库)
            sqlSession.commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
    }

    // 修改一个用户
    @Test
    public void updateUser() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        String string = UUID.randomUUID().toString();

        try {
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            boolean res = mapper.updateUser(new User(2,string,"pwd"+string));
            if (res) {
                System.out.println("修改成功!!!");
            }
            // 提交事务
            sqlSession.commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
    }

    // 删除一个用户
    @Test
    public void deleteUser() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        try {
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            boolean res = mapper.deleteUser(2);
            if (res) {
                System.out.println("删除成功!!!");
            }
            // 提交事务
            sqlSession.commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
    }
}
上一篇:Mybatis 日志工厂


下一篇:谷粒微博:需求、设计及代码框架