Mybatis XML方式的基本用法

創建項目

  • 創建Maven項目
  • 添加Mybatis依賴
<!--mybatis-->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.3</version>
</dependency>
  • 添加Log4j、JUnit和Mysql依賴
<!--mysql-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.46</version>
</dependency>

<!--測試-->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

<!--日志-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.26</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.26</version>
</dependency>
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

配置Mybatis

創建配置文件

在src/main/resources下創建mabatis-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>

    <settings>
        <!--指定使用log4j輸出日志-->
        <setting name="logImpl" value="LOG4J"/>
    </settings>

    <typeAliases>
        <!--配置包的別名
           這樣在使用類的時候, 不需要寫包名部分,只寫類型即可
        -->
        <package name="com._54programer.xml.domain"/>
    </typeAliases>

    <!--數據庫配置-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="UNPOOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value=""/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!--方式1
            配置完整路徑的映射配置文件-->
        <mapper resource="com/_54programer/xml/mapper/UserMapper.xml"/>
        <mapper resource="com/_54programer/xml/mapper/RoleMapper.xml"/>
        <!--方式2
            這種配置方式, 會先去查找com._54programer.xml.mapper包下所以的接口
            然后循環所有接口, 將接口com._54programer.xml.mapper.UserMapper轉為還com/_54programer/xml/mapper/UserMapper.xml
            然后搜索xml資源, 搜到就解析xml
        -->
        <!-- 
        <package name="com._54programer.xml.mapper"/> -->
    </mappers>

</configuration>
創建數據庫表、實體類和映射文件
  • 數據庫表
CREATE TABLE `sys_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用戶ID',
  `user_name` varchar(50) DEFAULT NULL COMMENT '用戶名',
  `user_password` varchar(50) DEFAULT NULL COMMENT '密碼',
  `user_email` varchar(50) DEFAULT 'test@qq.com' COMMENT '郵箱',
  `user_info` text DEFAULT NULL COMMENT '簡介',
  `head_img` blob DEFAULT NULL COMMENT '頭像',
  `create_time` datetime DEFAULT NULL COMMENT '創建時間',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用戶表' |
CREATE TABLE `sys_role` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '角色ID',
  `role_name` varchar(50) DEFAULT NULL COMMENT '角色名',
  `enabled` int(11) DEFAULT NULL COMMENT '有效標志',
  `create_by` bigint(20) DEFAULT NULL COMMENT '創建人',
  `create_time` datetime DEFAULT NULL COMMENT '創建時間',
  PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色表' |
CREATE TABLE `sys_user_role` (
  `user_id` bigint(20) DEFAULT NULL COMMENT '用戶ID',
  `role_id` bigint(20) DEFAULT NULL COMMENT '角色ID'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用戶角色關聯表'
  • 實體類
/**
 * 用戶表
 */
public class SysUser implements Serializable {
    /**
     * 用戶ID
     * 不要使用基本數據類型
     * 原因: 如果使用long id, 那么id默認為0, 如果在動態語句中使用 id != null進行判斷, 結果總會為true
     */
    private Long id;
    /**
     * 用戶名
     */
    private String userName;
    /**
     * 密碼
     */
    private String userPassword;
    /**
     * 郵箱
     */
    private String userEmail;
    /**
     * 簡介
     */
    private String userInfo;
    /**
     * 頭像
     * byte[] 這個類型一般對應數據庫中的BLOB、LONGVARBINARY以及一些二進制流有關的字段類型
     */
    private byte[] headImg;
    /**
     * 創建時間
     */
    private Date createTime;

    省略getter、setter方法
}
/**
 * 角色表
 */
public class SysRole implements Serializable {
    /**
     * 角色ID
     */
    private Long id;
    /**
     * 角色名
     */
    private String roleName;
    /**
     * 有效標志
     */
    private Integer enabled;
    /**
     * 創建人
     */
    private String createBy;
    /**
     * 創建時間
     */
    private Date createTime;
    省略getter、setter方法
}
  • 映射文件

/resources/com/_54programer/xml/mapper/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">
<mapper namespace="com._54programer.xml.mapper.UserMapper">

</mapper>

/resources/com/_54programer/xml/mapper/RoleMapper.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">
<mapper namespace="com._54programer.xml.mapper.RoleMapper">

</mapper>
  • 配置Log4j

/resources/log4j.properties

# 全局配置
log4j.rootLogger=ERROR, stdout

# mybatis日志配置
# mybatis日志最低級別是TRACE,在這個日志級別下,會輸出sql執行的詳細信息,特別適合在開發時使用
log4j.logger.com._54programer.xml.mapper=TRACE

# 控制臺輸出配置
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

到這個我們的Mybatis環境就配置好了

使用Mybatis進行增刪該查

Select用法
  • 根據ID查詢用戶信息
package com._54programer.xml.mapper;
import com._54programer.xml.domain.SysUser;

public interface UserMapper {
    SysUser selectById(Long id);
}
<?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 namespace="com._54programer.xml.mapper.UserMapper">
    <!--
        resultMap: 用于配置java對象的屬性和查詢結果列的對應關系
        id: 跟select中resultMap對應
        type: java對象類型
        property: java對象屬性
        column: 數據庫列名
        jdbcType: 列對應的數據庫類型
    -->
    <resultMap id="userMap" type="com._54programer.xml.domain.SysUser">
        <id property="id" column="id"/>
        <result property="userName" column="user_name"/>
        <result property="userPassword" column="user_password"/>
        <result property="userEmail" column="user_email"/>
        <result property="userInfo" column="user_info"/>
        <result property="headImg" column="head_img" jdbcType="BLOB"/>
        <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
    </resultMap>
    <!--
        select: 查詢標簽
        id: 唯一標示符,通過id關聯接口中的方法
        resultMap: 設置返回值的類型和映射關系
        #{id}: mybatis中預編譯參數的一種方式, id是參數名
    -->
    <select id="selectById" resultMap="userMap">
        select * from sys_user where id = #{id}
    </select>
</mapper>
package com._54programer.xml.mapper;

import com._54programer.xml.domain.SysUser;
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 org.junit.BeforeClass;
import org.junit.Test;

import java.io.IOException;
import java.io.Reader;

public class UserMapperTest {

    private static SqlSessionFactory sqlSessionFactory;

    @BeforeClass
    public static void init(){
        try {
            //1.通過Resources工具類將mybatis-config.xml讀入Reader
            Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
            //2.創建SqlSessionFactory, 在創建SqlSessionFactory的過程中
            //首先解析mybatis-config.xml配置文件, 然后根據mappers配置讀取全部的Mapper.xml進行具體的解析
            //解析完成后, 創建SqlSessionFactory就具有所有的屬性配置和執行sql的信息
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void TestSelectById(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        SysUser sysUser = mapper.selectById(1L);
        sqlSession.close();
    }
}

運行輸出:
DEBUG [main] - ==>  Preparing: select * from sys_user where id = ? 
DEBUG [main] - ==> Parameters: 1(Long)
TRACE [main] - <==    Columns: id, user_name, user_password, user_email, user_info, head_img, create_time
TRACE [main] - <==        Row: 1, admin, 123456, admin@qq.com, <<BLOB>>, <<BLOB>>, 2016-06-07 01:11:12.0
DEBUG [main] - <==      Total: 1
  • 查詢全部用戶信息
public interface UserMapper {
    List<SysUser> selectAll();
}
<?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">
<mapper namespace="com._54programer.xml.mapper.UserMapper">

    <!--
        resultType: 返回值類型
    -->
    <select id="selectAll" resultType="com._54programer.xml.domain.SysUser">
        select id,
            user_name userName,
            user_password userPassword,
            user_email userEmail,
            user_info userInfo,
            head_img headImg,
            create_time createTime
            from sys_user
    </select>

</mapper>
@Test
public void TestSelectAll(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<SysUser> sysUsers = mapper.selectAll();
    sqlSession.close();
}

輸出:
DEBUG [main] - ==>  Preparing: select id, user_name userName, user_password userPassword, user_email userEmail, user_info userInfo, head_img headImg, create_time createTime from sys_user 
DEBUG [main] - ==> Parameters: 
TRACE [main] - <==    Columns: id, userName, userPassword, userEmail, userInfo, headImg, createTime
TRACE [main] - <==        Row: 1, admin, 123456, admin@qq.com, <<BLOB>>, <<BLOB>>, 2016-06-07 01:11:12.0
TRACE [main] - <==        Row: 1001, test, 123456, test@qq.com, <<BLOB>>, <<BLOB>>, 2016-06-07 00:00:00.0
DEBUG [main] - <==      Total: 2

Mybatis可以自動將以下畫線方式命名的數據庫列映射到Java對象的駝峰式命名屬性中。所以我們還可以這樣寫

<select id="selectAll" resultType="com._54programer.xml.domain.SysUser">
    select id,
        user_name,
        user_password,
        user_email,
        user_info,
        head_img,
        create_time
        from sys_user
</select>
@Test
public void TestSelectAll(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<SysUser> sysUsers = mapper.selectAll();
    sqlSession.close();
}

輸出:
DEBUG [main] - ==>  Preparing: select id, user_name, user_password, user_email, user_info, head_img, create_time from sys_user 
DEBUG [main] - ==> Parameters: 
TRACE [main] - <==    Columns: id, user_name, user_password, user_email, user_info, head_img, create_time
TRACE [main] - <==        Row: 1, admin, 123456, admin@qq.com, <<BLOB>>, <<BLOB>>, 2016-06-07 01:11:12.0
TRACE [main] - <==        Row: 1001, test, 123456, test@qq.com, <<BLOB>>, <<BLOB>>, 2016-06-07 00:00:00.0
DEBUG [main] - <==      Total: 2
  • 多表關聯查詢

方式1: 重新定義一個繼承SysUser的擴展類SysUserExtend

public class SysUserExtend extends SysUser {
    private String roleName;

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }
}
public interface UserMapper {
    List<SysUserExtend> selectUserRole(Long id);
}
<select id="selectUserRole" resultType="com._54programer.xml.domain.SysUserExtend">
    SELECT
    u.id, u.user_email, u.user_info, u.user_name, u.user_password, u.head_img, u.create_time,
    r.role_name
    from sys_user u
    LEFT JOIN sys_user_role ur on u.id = ur.user_id
    LEFT JOIN sys_role r on r.id = ur.role_id
    WHERE u.id = #{id}
</select>
@Test
public void TestselectUserRole(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<SysUserExtend> sysUserExtends = mapper.selectUserRole(1L);
    sqlSession.close();
}

輸出:
DEBUG [main] - ==>  Preparing: SELECT u.id, u.user_email, u.user_info, u.user_name, u.user_password, u.head_img, u.create_time, r.role_name from sys_user u LEFT JOIN sys_user_role ur on u.id = ur.user_id LEFT JOIN sys_role r on r.id = ur.role_id WHERE u.id = ? 
DEBUG [main] - ==> Parameters: 1(Long)
TRACE [main] - <==    Columns: id, user_email, user_info, user_name, user_password, head_img, create_time, role_name
TRACE [main] - <==        Row: 1, admin@qq.com, <<BLOB>>, admin, 123456, <<BLOB>>, 2016-06-07 01:11:12.0, 管理員
TRACE [main] - <==        Row: 1, admin@qq.com, <<BLOB>>, admin, 123456, <<BLOB>>, 2016-06-07 01:11:12.0, 普通用戶
DEBUG [main] - <==      Total: 2

方式2: 在SysUser中增加SysRole對象

public class SysUser implements Serializable {

    private Long id;
    private String userName;
    private String userPassword;
    private String userEmail;
    private String userInfo;
    private byte[] headImg;
    private Date createTime;

    //在SysUser中增加SysRole對象
    private SysRole role;

public interface UserMapper {
    List<SysUser> selectUserRole(Long id);
}
<select id="selectUserRole" resultType="com._54programer.xml.domain.SysUser">
    SELECT
    u.id, u.user_email, u.user_info, u.user_name, u.user_password, u.head_img, u.create_time,
    r.role_name as "role.roleName"
    from sys_user u
    LEFT JOIN sys_user_role ur on u.id = ur.user_id
    LEFT JOIN sys_role r on r.id = ur.role_id
    WHERE u.id = #{id}
</select>
@Test
public void TestselectUserRole(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    mapper.selectUserRole(1L);
    sqlSession.close();
}

輸出:
DEBUG [main] - ==>  Preparing: SELECT u.id, u.user_email, u.user_info, u.user_name, u.user_password, u.head_img, u.create_time, r.role_name as "role.roleName" from sys_user u LEFT JOIN sys_user_role ur on u.id = ur.user_id LEFT JOIN sys_role r on r.id = ur.role_id WHERE u.id = ? 
DEBUG [main] - ==> Parameters: 1(Long)
TRACE [main] - <==    Columns: id, user_email, user_info, user_name, user_password, head_img, create_time, role.roleName
TRACE [main] - <==        Row: 1, admin@qq.com, <<BLOB>>, admin, 123456, <<BLOB>>, 2016-06-07 01:11:12.0, 管理員
TRACE [main] - <==        Row: 1, admin@qq.com, <<BLOB>>, admin, 123456, <<BLOB>>, 2016-06-07 01:11:12.0, 普通用戶
DEBUG [main] - <==      Total: 2
Insert
  • 插入一條數據
public interface UserMapper {
    int addUser(SysUser sysUser);
}
<insert id="addUser">
    insert into sys_user(
        id, user_name, user_password, user_email, user_info, head_img, create_time)
    values(
        #{id}, #{userName}, #{userPassword}, #{userEmail},
        #{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP}
    )
</insert>
@Test
public void TestAddUser(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    SysUser sysUser = new SysUser();
    sysUser.setCreateTime(new Date());
    sysUser.setUserEmail("test1@qq.com");
    sysUser.setUserInfo("test1...");
    sysUser.setUserName("sn");
    sysUser.setUserPassword("123456");
    mapper.addUser(sysUser);
    sqlSession.commit();
    sqlSession.close();
}

輸出:
DEBUG [main] - ==>  Preparing: insert into sys_user( id, user_name, user_password, user_email, user_info, head_img, create_time) values( ?, ?, ?, ?, ?, ?, ? ) 
DEBUG [main] - ==> Parameters: null, sn(String), 123456(String), test1@qq.com(String), test1...(String), null, 2019-11-19 13:41:03.726(Timestamp)
DEBUG [main] - <==    Updates: 1
  • 使用JDBC方式返回主鍵ID
    這種回寫主鍵的方法只適用于支持主鍵自增的數據庫。有些數據庫(如 Oracle )不提供主鍵自增的功能。
public interface UserMapper {
    int addUserGetId(SysUser sysUser);
}
<!--
    useGeneratedKeys: 設為true, Mybatis會使用JDBC的getGeneratedKeys方法來獲取數據庫內部生成的主鍵
    獲得主鍵后將其賦值給keyProperty配置的id屬性
-->
<insert id="addUserGetId" useGeneratedKeys="true" keyProperty="id">
    insert into sys_user(
        id, user_name, user_password, user_email, user_info, head_img, create_time)
    values(
        #{id}, #{userName}, #{userPassword}, #{userEmail},
        #{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP}
    )
</insert>
@Test
public void TestaddUserGetId(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    SysUser sysUser = new SysUser();
    sysUser.setCreateTime(new Date());
    sysUser.setUserEmail("test1@qq.com");
    sysUser.setUserInfo("test1...");
    sysUser.setUserName("sn");
    sysUser.setUserPassword("123456");
    mapper.addUserGetId(sysUser);
    //輸出新增記錄的ID
    System.out.println("主鍵ID: "+sysUser.getId());
    sqlSession.commit();
    sqlSession.close();
}
輸出:
DEBUG [main] - ==>  Preparing: insert into sys_user( id, user_name, user_password, user_email, user_info, head_img, create_time) values( ?, ?, ?, ?, ?, ?, ? ) 
DEBUG [main] - ==> Parameters: null, sn(String), 123456(String), test1@qq.com(String), test1...(String), null, 2019-11-19 13:50:06.426(Timestamp)
DEBUG [main] - <==    Updates: 1
主鍵ID: 1037
  • 使用selectKey返回主鍵ID
    這種方式不僅適用于不提供主鍵自增功能的數據庫,也適用于提供主鍵自增功能的數據庫。
<!--
    resultType: 返回值類型
    order: order屬性的設置和使用的數據庫有關, 在mysql數據庫中, order屬性值設置AFTER,
           因為當前記錄的主鍵值在insert語句執行成功后才能獲取, 在Oracle, order的值要
           設置為BEFORE, 因為Oracle中需要先從序列獲取值然后再作為主鍵插入到數據庫中
-->
<insert id="addUserGetId">
    insert into sys_user(
        id, user_name, user_password, user_email, user_info, head_img, create_time)
    values(
        #{id}, #{userName}, #{userPassword}, #{userEmail},
        #{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP}
    )
    <selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER">
        select last_insert_id()
    </selectKey>
</insert>
@Test
public void TestaddUserGetId(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    SysUser sysUser = new SysUser();
    sysUser.setCreateTime(new Date());
    sysUser.setUserEmail("test1@qq.com");
    sysUser.setUserInfo("test1...");
    sysUser.setUserName("sn");
    sysUser.setUserPassword("123456");
    mapper.addUserGetId(sysUser);
    //輸出新增記錄的ID
    System.out.println(sysUser.getId());
    sqlSession.commit();
    sqlSession.close();
}

輸出:
DEBUG [main] - ==>  Preparing: insert into sys_user( id, user_name, user_password, user_email, user_info, head_img, create_time) values( ?, ?, ?, ?, ?, ?, ? ) 
DEBUG [main] - ==> Parameters: null, sn(String), 123456(String), test1@qq.com(String), test1...(String), null, 2019-11-19 14:00:07.414(Timestamp)
DEBUG [main] - <==    Updates: 1
DEBUG [main] - ==>  Preparing: select last_insert_id() 
DEBUG [main] - ==> Parameters: 
TRACE [main] - <==    Columns: last_insert_id()
TRACE [main] - <==        Row: 1038
DEBUG [main] - <==      Total: 1
1038
Update
public interface UserMapper {
    int updateUserById(SysUser sysUser);
}
<update id="updateUserById">
    update sys_user
    set user_name = #{userName},
        user_password = #{userPassword},
        user_email = #{userEmail},
        user_info = #{userInfo},
        head_img = #{headImg, jdbcType=BLOB},
        create_time = #{createTime, jdbcType=TIMESTAMP}
    where id = #{id}
</update>
@Test
public void TestUpdateUserById(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    SysUser sysUser = new SysUser();
    sysUser.setId(1037L);
    sysUser.setCreateTime(new Date());
    sysUser.setUserEmail("test2@qq.com");
    sysUser.setUserInfo("test2...");
    sysUser.setUserName("sn");
    sysUser.setUserPassword("123456789");
    int result = mapper.updateUserById(sysUser);
    System.out.println(result);
    sqlSession.commit();
    sqlSession.close();
}
輸出:
DEBUG [main] - ==>  Preparing: update sys_user set user_name = ?, user_password = ?, user_email = ?, user_info = ?, head_img = ?, create_time = ? where id = ? 
DEBUG [main] - ==> Parameters: sn(String), 123456789(String), test2@qq.com(String), test2...(String), null, 2019-11-19 14:13:50.226(Timestamp), 1037(Long)
DEBUG [main] - <==    Updates: 1
1
Delete
public interface UserMapper {
    int deleteUserById(Long id);
}
<update id="deleteUserById">
    delete from sys_user where id = #{id}
</update>
@Test
public void TestDeleteUserById(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    int result = mapper.deleteUserById(1037L);
    System.out.println(result);
    sqlSession.commit();
    sqlSession.close();
}
輸出:
DEBUG [main] - ==>  Preparing: delete from sys_user where id = ? 
DEBUG [main] - ==> Parameters: 1037(Long)
DEBUG [main] - <==    Updates: 1
1
多參數

我們嘗試下傳多個參數進行數據查詢

public interface UserMapper {
    SysUser findUserByIdAndUsername(Long id, String user_name);
}
<select id="findUserByIdAndUsername" resultType="com._54programer.xml.domain.SysUser">
    select id,
        user_name,
        user_password,
        user_email,
        user_info,
        head_img,
        create_time
        from sys_user
        where id = #{id} and user_name = #{user_name}
</select>
@Test
public void TestFindByIdAndUsername(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    SysUser sysUser = mapper.findUserByIdAndUsername(1L, "admin");
    sqlSession.close();
}

運行:
報錯了!!!
org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: org.apache.ibatis.binding.BindingException: 
Parameter 'id' not found. Available parameters are [arg1, arg0, param1, param2]

怎么解決? 在參數錢添加@Param注解即可。

public interface UserMapper {
    SysUser findUserByIdAndUsername(@Param("id") Long id, @Param("user_name") String user_name);
}

再測試,這次成功了

DEBUG [main] - ==>  Preparing: select id, user_name, user_password, user_email, user_info, head_img, create_time from sys_user where id = ? and user_name = ? 
DEBUG [main] - ==> Parameters: 1(Long), admin(String)
TRACE [main] - <==    Columns: id, user_name, user_password, user_email, user_info, head_img, create_time
TRACE [main] - <==        Row: 1, admin, 123456, admin@qq.com, <<BLOB>>, <<BLOB>>, 2016-06-07 01:11:12.0
DEBUG [main] - <==      Total: 1

給參數配置@Param注解后,Mybatis就會自動將參數封裝成Map類型,@param會作為Map中的key,因此sql就可以通過配置的注解值來使用參數。

Mybatis動態SQL

if
  • 查詢條件
<!--
    test: 必須屬性, 屬性值是一個符合OGNL要求的判斷表達式
    userName != null : 適用于任何類型, 用于判斷屬性值是否為空
    userName != '' : 僅適用于字符串類型, 用于判斷是否為空字符串
    and or : 相當于 && ||
-->
<select id="selectByUser" resultType="com._54programer.xml.domain.SysUser">
    select id,
        user_name,
        user_password,
        user_email,
        user_info,
        head_img,
        create_time
        from sys_user
        where 1=1
        <if test="userName != null and userName != ''">
            and user_name like concat('%', #{userName}, '%')
        </if>
        <if test="userEmail != null and userEmail != ''">
            and user_email = #{userEmail}
        </if>
</select>
  • 更新字段
<!--
    每個if標簽的sql語句后面都有一個逗號
    如果全部為null或'', 就會報錯, 所以在最后拼接了一個id = #{id}
-->
<update id="updateUserById">
    update sys_user
    set
        <if test="userName != null and userName != ''">
        user_name = #{userName},
        </if>
        <if test="userPassword != null and userPassword != ''">
        user_password = #{userPassword},
        </if>
        <if test="userEmail != null and userEmail != ''">
        user_email = #{userEmail},
        </if>
        <if test="userInfo != null and userInfo != ''">
        user_info = #{userInfo},
        </if>
        <if test="headImg != null">
        head_img = #{headImg, jdbcType=BLOB},
        </if>
        <if test="createTime != null">
        create_time = #{createTime, jdbcType=TIMESTAMP},
        </if>
        id = #{id}
    where id = #{id}
</update>
choose
<!--
    choose when otherwise
    可以讓邏輯更為嚴密
    加入userName=null或'', 會查詢出所有用戶的信息
-->
<select id="selectByUser" resultType="com._54programer.xml.domain.SysUser">
    select id,
    user_name,
    user_password,
    user_email,
    user_info,
    head_img,
    create_time
    from sys_user
    where 1=1
    <choose>
        <when test="userName != null and userName != ''">
            and user_name = #{userName}
        </when>
        <otherwise>
            and 1=2
        </otherwise>
    </choose>
</select>
where
<!--
    where里都不成立, 不會拼接where 1=1
    where里有條件成立, 會自動拼接where 1=1
-->
<select id="selectByUser" resultType="com._54programer.xml.domain.SysUser">
    select id,
    user_name,
    user_password,
    user_email,
    user_info,
    head_img,
    create_time
    from sys_user
    <where>
        <if test="userName != null and userName != ''">
            and user_name like concat('%', #{userName}, '%')
        </if>
        <if test="userEmail != null and userEmail != ''">
            and user_email = #{userEmail}
        </if>
    </where>
</select>
foreach
  • in查詢
<!--
    collection: 循環迭代的屬性名
    item: 變量名,值為從法代對象中取出的每一個值。
    index: 索引的屬性名
    open: 整個循環內容開頭的字符串
    close: 整個循環內容結尾的字符串
    separator: 每次循環的分隔符
-->
<select id="selectByID" resultType="com._54programer.xml.domain.SysUser">
    select id,
        user_name,
        user_password,
        user_email,
        user_info,
        head_img,
        create_time
        from sys_user
        where id in
        <foreach collection="list" open="(" close=")" separator="," item="id" index="i">
            #{id}
        </foreach>
</select>
  • 批量插入
<insert id="addUser">
    insert into sys_user(
        id, user_name, user_password, user_email, user_info, head_img, create_time)
    values(
    <foreach collection="list" item="user" separator=",">
        #{user.id}, #{user.userName}, #{user.userPassword}, #{user.userEmail},
        #{user.userInfo}, #{user.headImg, jdbcType=BLOB}, #{user.createTime, jdbcType=TIMESTAMP}
    </foreach>
    )
</insert>
  • 動態更新
<!--
    MyBati在內部的上下文中默認值_parameter
-->
<update id="updateUserById">
    update sys_user
    set
    <foreach collection="_parameter" item="val" index="key" separator=",">
        ${key} = #{val}
    </foreach>
    where id = #{id}
</update>

Mapper接口動態代理實現原理

我們可能會有一個疑問,為什么Mapper接口沒有實現類卻能被正常使用?
這是因為Mybatis在Mapper接口上使用了動態代理。

這是我們剛才定義的一個Mapper接口:

public interface UserMapper {
    List<SysUser> selectAll();
}

我們使用Java動態代理方式創建一個代理類

public class MyMapperProxy<T> implements InvocationHandler {

    private Class<T> mapperInterface;
    private SqlSession sqlSession;

    public MyMapperProxy(Class<T> mapperInterface, SqlSession sqlSession) {
        this.mapperInterface = mapperInterface;
        this.sqlSession = sqlSession;
    }

    /**
     * 這里只是簡單實現
     * 不考慮接口方法中的參數和方法的返回值
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        List<T> list = sqlSession.selectList(mapperInterface.getCanonicalName() + "." + method.getName());
        return list;
    }

}
@Test
public void Test1(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    MyMapperProxy userMapperProxy = new MyMapperProxy(UserMapper.class, sqlSession);
    UserMapper userMapper = (UserMapper) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{UserMapper.class}, userMapperProxy);
    userMapper.selectAll();
    sqlSession.close();
}

輸出:
DEBUG [main] - ==>  Preparing: select id, user_name, user_password, user_email, user_info, head_img, create_time from sys_user 
DEBUG [main] - ==> Parameters: 
TRACE [main] - <==    Columns: id, user_name, user_password, user_email, user_info, head_img, create_time
TRACE [main] - <==        Row: 1, admin, 123456, admin@qq.com, <<BLOB>>, <<BLOB>>, 2016-06-07 01:11:12.0
TRACE [main] - <==        Row: 1001, test, 123456, test@qq.com, <<BLOB>>, <<BLOB>>, 2016-06-07 00:00:00.0
TRACE [main] - <==        Row: 1036, sn, 123456, test1@qq.com, <<BLOB>>, <<BLOB>>, 2019-11-19 13:41:03.0
TRACE [main] - <==        Row: 1038, sn, 123456, test1@qq.com, <<BLOB>>, <<BLOB>>, 2019-11-19 14:00:07.0
DEBUG [main] - <==      Total: 4

從代理類中可以看到,當調用一個接口的方法時,會先通過接口的全限定名稱和當前調用的方法名的組合得到這個方法id ,這個 id 的值就是映射 XML中namespace 和具體方法 id的組合。所以可以在代理方法中使用 sqlSession 以命名空間的方式調用方法。通過這種方式可以將接口和 XML 文件中的方法關聯起來。這種代理方式和常規代理的不同之處在于,這里沒有對某個具體類進行代理,而是通過代理轉化成了對其他代碼的調用。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容