JAVAEE——Mybatis(Mybatis介紹配置使用以及與Spring整合)

Mybatis介紹

MyBatis 本是apache的一個(gè)開源項(xiàng)目iBatis, 2010年這個(gè)項(xiàng)目由apache software foundation 遷移到了google code,并且改名為MyBatis 。2013年11月遷移到Github。
MyBatis是一個(gè)優(yōu)秀的持久層框架,它對(duì)jdbc的操作數(shù)據(jù)庫的過程進(jìn)行封裝,使開發(fā)者只需要關(guān)注 SQL 本身,而不需要花費(fèi)精力去處理例如注冊(cè)驅(qū)動(dòng)、創(chuàng)建connection、創(chuàng)建statement、手動(dòng)設(shè)置參數(shù)、結(jié)果集檢索等jdbc繁雜的過程代碼。
Mybatis通過xml或注解的方式將要執(zhí)行的各種statement(statement、preparedStatemnt、CallableStatement)配置起來,并通過java對(duì)象和statement中的sql進(jìn)行映射生成最終執(zhí)行的sql語句,最后由mybatis框架執(zhí)行sql并將結(jié)果映射成java對(duì)象并返回。

JDBC存在的問題

1、 數(shù)據(jù)庫連接創(chuàng)建、釋放頻繁造成系統(tǒng)資源浪費(fèi),從而影響系統(tǒng)性能。如果使用數(shù)據(jù)庫連接池可解決此問題。
2、 Sql語句在代碼中硬編碼,造成代碼不易維護(hù),實(shí)際應(yīng)用中sql變化的可能較大,sql變動(dòng)需要改變java代碼。
3、 使用preparedStatement向占有位符號(hào)傳參數(shù)存在硬編碼,因?yàn)閟ql語句的where條件不一定,可能多也可能少,修改sql還要修改代碼,系統(tǒng)不易維護(hù)。
4、 對(duì)結(jié)果集解析存在硬編碼(查詢列名),sql變化導(dǎo)致解析代碼變化,系統(tǒng)不易維護(hù),如果能將數(shù)據(jù)庫記錄封裝成pojo對(duì)象解析比較方便。

Mybatis架構(gòu)

Mybatis架構(gòu)

Mybatis使用

mybaits的代碼由github.com管理

下載地址:https://github.com/mybatis/mybatis-3/releases

mybatis如下:


圖片.png

目錄結(jié)構(gòu)

  • mybatis-3.2.7.jar mybatis的核心包
  • lib文件夾 mybatis的依賴包所在
  • mybatis-3.2.7.pdf mybatis使用手冊(cè)

創(chuàng)建核心配置文件

<?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>
    <!-- 和spring整合后 environments配置將廢除 -->
    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事務(wù)管理 -->
            <transactionManager type="JDBC" />
            <!-- 數(shù)據(jù)庫連接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url"
                          value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
                <property name="username" value="root" />
                <property name="password" value="root" />
            </dataSource>
        </environment>
    </environments>
</configuration>

  • src目錄下創(chuàng)建log4j.properties jdbc.properties
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

  • 創(chuàng)建pojo映射文件 User.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="test">
    <select id="queryUserById" parameterType="Integer" resultType="cn.probuing.mybatisintro.pojo.User">
        SELECT *
        FROM `user`
        WHERE id = #{v}
    </select>
</mapper>

標(biāo)簽解釋

在pojo的映射文件xml中,包含<select>、<insert>、<update>、<delete> 分別對(duì)應(yīng) 查詢、添加、更新、刪除操作

  • 其中 id 代表對(duì)應(yīng)標(biāo)簽的識(shí)別id
  • parameterType代表占位符的類型
  • resultType 代表返回值類型

語句解釋

#{v}代表占位符 占位符標(biāo)識(shí)為v
${value}代表字符串拼接 標(biāo)識(shí)必須為value

select * from user where username like '%xx%'
  • 對(duì)應(yīng)的UserMap.xml配置文件中的SQL文件寫法
SELECT * FROM `user` where username like "%"#{v}"%"
  • 測試代碼
@Test
    public void testSelectOne() throws IOException {
        //創(chuàng)建SqlSessionFactoryBuilder對(duì)象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

        //加載SqlMapConfig.xml配置文件 創(chuàng)建SqlSessionFactory
        SqlSessionFactory sessionFactory = builder.build(Resources.getResourceAsStream("SqlMapConfig.xml"));
        //創(chuàng)建SqlSession對(duì)象
        SqlSession sqlSession = sessionFactory.openSession();
        //SqlSession執(zhí)行對(duì)象查詢
        User user = (User) sqlSession.selectOne("queryUserById", 1);
        System.out.println(user);
        //釋放資源
        sqlSession.close();
    }

insert

  • 映射文件 mapper sql書寫
   <insert id="insertUser" parameterType="cn.probuing.mybatisintro.pojo.User">
        <!-- 返回最后插入的主鍵id -->
        <selectKey keyProperty="id" resultType="Integer" order="AFTER">
            SELECT LAST_INSERT_ID()
        </selectKey>
        insert into user(username,birthday,address,sex) values(#{username},#{birthday},#{address},#{sex})
    </insert>

update

  • 映射文件 mapper sql
<!--更新用戶-->
    <update id="updateUserById" parameterType="cn.probuing.mybatisintro.pojo.User">
        update user
        set username=#{username},ses=#{sex},birthday=#{birthday},address=#{address}
        where id = #{id}
    </update>
  • 測試代碼
  @Test
    public void testUpdateUserById() throws IOException {
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sessionFactory = builder.build(Resources.getResourceAsStream("sqlMapConfig.xml"));
        SqlSession sqlSession = sessionFactory.openSession();
        User user = new User();
        user.setId(33);
        user.setUsername("www33333");
        user.setSex("釹");
        user.setBirthday(new Date());
        user.setAddress("332211aasss");
        int line = sqlSession.insert("test.updateUserById", user);
        sqlSession.commit();
        System.out.println(line);
    }

delete

  • Mapper映射文件
  <!--刪除用戶-->
    <delete id="deleteUserById" parameterType="Integer">
        DELETE from user
        WHERE id = #{vvvv}
    </delete>
  • 測試代碼
 @Test
    public void testDeleteUserById() throws IOException {
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sessionFactory = builder.build(Resources.getResourceAsStream("sqlMapConfig.xml"));
        SqlSession sqlSession = sessionFactory.openSession();
        sqlSession.delete("test.deleteUserById", 32);
        sqlSession.commit();
    }

MyBatis 解決JDBC的需求

1、數(shù)據(jù)庫連接創(chuàng)建、釋放頻繁造成系統(tǒng)資源浪費(fèi)從而影響系統(tǒng)性能,如果使用數(shù)據(jù)庫連接池可解決此問題。
解決:在SqlMapConfig.xml中配置數(shù)據(jù)連接池,使用連接池管理數(shù)據(jù)庫鏈接。
2、Sql語句寫在代碼中造成代碼不易維護(hù),實(shí)際應(yīng)用sql變化的可能較大,sql變動(dòng)需要改變java代碼。
解決:將Sql語句配置在XXXXmapper.xml文件中與java代碼分離。
3、向sql語句傳參數(shù)麻煩,因?yàn)閟ql語句的where條件不一定,可能多也可能少,占位符需要和參數(shù)一一對(duì)應(yīng)。
解決:Mybatis自動(dòng)將java對(duì)象映射至sql語句,通過statement中的parameterType定義輸入?yún)?shù)的類型。
4、對(duì)結(jié)果集解析麻煩,sql變化導(dǎo)致解析代碼變化,且解析前需要遍歷,如果能將數(shù)據(jù)庫記錄封裝成pojo對(duì)象解析比較方便。
解決:Mybatis自動(dòng)將sql執(zhí)行結(jié)果映射至java對(duì)象,通過statement中的resultType定義輸出結(jié)果的類型

提出一個(gè)需求

MyBatis與HIbernate的不同

Mybatis和hibernate不同,它不完全是一個(gè)ORM框架,因?yàn)镸yBatis需要程序員自己編寫Sql語句。mybatis可以通過XML或注解方式靈活配置要運(yùn)行的sql語句,并將java對(duì)象和sql語句映射生成最終執(zhí)行的sql,最后將sql執(zhí)行的結(jié)果再映射生成java對(duì)象。

Mybatis學(xué)習(xí)門檻低,簡單易學(xué),程序員直接編寫原生態(tài)sql,可嚴(yán)格控制sql執(zhí)行性能,靈活度高,非常適合對(duì)關(guān)系數(shù)據(jù)模型要求不高的軟件開發(fā),例如互聯(lián)網(wǎng)軟件、企業(yè)運(yùn)營類軟件等,因?yàn)檫@類軟件需求變化頻繁,一但需求變化要求成果輸出迅速。但是靈活的前提是mybatis無法做到數(shù)據(jù)庫無關(guān)性,如果需要實(shí)現(xiàn)支持多種數(shù)據(jù)庫的軟件則需要自定義多套sql映射文件,工作量大。

Hibernate對(duì)象/關(guān)系映射能力強(qiáng),數(shù)據(jù)庫無關(guān)性好,對(duì)于關(guān)系模型要求高的軟件(例如需求固定的定制化軟件)如果用hibernate開發(fā)可以節(jié)省很多代碼,提高效率。但是Hibernate的學(xué)習(xí)門檻高,要精通門檻更高,而且怎么設(shè)計(jì)O/R映射,在性能和對(duì)象模型之間如何權(quán)衡,以及怎樣用好Hibernate需要具有很強(qiáng)的經(jīng)驗(yàn)和能力才行。
總之,按照用戶的需求在有限的資源環(huán)境下只要能做出維護(hù)性、擴(kuò)展性良好的軟件架構(gòu)都是好架構(gòu),所以框架只有適合才是最好。

Mapper動(dòng)態(tài)代理方式開發(fā)

開發(fā)規(guī)范

Mapper接口開發(fā)方法只需要程序員編寫Mapper接口(相當(dāng)于Dao接口),由Mybatis框架根據(jù)接口定義創(chuàng)建接口的動(dòng)態(tài)代理對(duì)象,代理對(duì)象的方法體同上邊Dao接口實(shí)現(xiàn)類方法。
Mapper接口開發(fā)需要遵循以下規(guī)范:

  • 1、 Mapper.xml文件中的namespace與mapper接口的類路徑相同。
  • 2、Mapper接口方法名和Mapper.xml中定義的每個(gè)statement的id相同
  • 3、Mapper接口方法的輸入?yún)?shù)類型和mapper.xml中定義的每個(gè)sql 的parameterType的類型相同
  • 4、Mapper接口方法的輸出參數(shù)類型和mapper.xml中定義的每個(gè)sql的resultType的類型相同

創(chuàng)建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="cn.probuing.mybatisintro.mapper.UserMapper">
    <!--根據(jù)id查詢用戶-->
    <select id="queryUserById" parameterType="int"
            resultType="cn.probuing.mybatisintro.pojo.User">
        select *
        from user
        where id = #{id}
    </select>

    <!--根據(jù)用戶名查詢用戶-->
    <select id="queryUserByName" parameterType="String"
            resultType="cn.probuing.mybatisintro.pojo.User">
        select *
        from user
        where username like '%${value}%'
    </select>
</mapper>

創(chuàng)建接口UserMapper

public interface UserMapper {
    public User queryUserById(int id);
    public List<User> queryUserByName(String userName);
}

核心配置文件加載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命名空間 用于隔離sql -->
<mapper namespace="cn.probuing.mybatisintro.mapper.UserMapper">
    <!--根據(jù)id查詢用戶-->
    <select id="queryUserById" parameterType="int"
            resultType="cn.probuing.mybatisintro.pojo.User">
        select *
        from user
        where id = #{id}
    </select>

    <!--根據(jù)用戶名查詢用戶-->
    <select id="queryUserByName" parameterType="String"
            resultType="cn.probuing.mybatisintro.pojo.User">
        select *
        from user
        where username like '%${value}%'
    </select>
</mapper>

測試代碼

 /**
     * 根據(jù)id查詢用戶
     */
    @Test
    public void testQueryUserById() throws IOException {
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sessionFactory = builder.build(Resources.getResourceAsStream("SqlMapConfig.xml"));
        SqlSession sqlSession = sessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = userMapper.queryUserById(31);
        System.out.println(user);
    }

    /**
     * 根據(jù)name查詢用戶列表
     * @throws IOException
     */
    @Test
    public void testQueryUserByname() throws IOException {
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = builder.build(Resources.getResourceAsStream("SqlMapConfig.xml"));
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = userMapper.queryUserByName("王");
        for (User user : userList) {
            System.out.println(user);
        }
    }

SqlMapConfig.xml配置文件詳解

配置內(nèi)容

SqlMapConfig.xml中配置的內(nèi)容和順序如下

  • properties(屬性)
  • settings(全局配置參數(shù))
  • typeAliases(類型別名)
  • typeHandlers(類型處理器)
  • objectFactory(對(duì)象工廠)
  • plugins(插件)
  • environments(環(huán)境集合屬性對(duì)象)
    • environment(環(huán)境子屬性對(duì)象)
      • transactionManager(事務(wù)管理)
      • dataSource(數(shù)據(jù)源)
  • mappers(映射器)

properties(屬性)

  • db.properties 配置文件內(nèi)容
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
  • SqlMapConfig.xml
    <!-- 是用resource屬性加載外部配置文件 -->
    <properties resource="db.properties">
        <!-- 在properties內(nèi)部用property定義屬性 -->
        <!-- 如果外部配置文件有該屬性,則內(nèi)部定義屬性被外部屬性覆蓋 -->
        <property name="jdbc.username" value="root123" />
        <property name="jdbc.password" value="root123" />
    </properties>
    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事務(wù)管理 -->
            <transactionManager type="JDBC" />
            <!-- 數(shù)據(jù)庫連接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>
    </environments>
    <!-- 加載映射文件 -->
    <mappers>
        <mapper resource="sqlmap/User.xml" />
        <mapper resource="mapper/UserMapper.xml" />
    </mappers>

tips
MyBatis將按照下面的順序來加載屬性

  • 在properties元素體內(nèi)定義的屬性首先被讀取
  • 然后會(huì)讀取properties元素中resource或url加載的屬性,它會(huì)覆蓋已讀取的同名屬性

typeAliases(類型別名)

mybatis支持別名

別名     映射的類型
_byte     byte 
_long     long 
_short    short 
_int      int 
_integer  int 
_double   double 
_float    float 
_boolean  boolean 
string    String 
byte      Byte 
long      Long 
short     Short 
int       Integer 
integer   Integer 
double    Double 
float     Float 
boolean   Boolean 
date      Date 
decimal   BigDecimal 
bigdecimal BigDecimal 
map       Map
自定義別名
  • SqlMapConfig.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>
    <!-- 是用resource屬性加載外部配置文件 -->
    <properties resource="db.properties">
        <!-- 在properties內(nèi)部用property定義屬性 -->
        <property name="jdbc.username" value="root123" />
        <property name="jdbc.password" value="root123" />
    </properties>

    <typeAliases>
        <!-- 單個(gè)別名定義 -->
        <typeAlias alias="user" type="cn.itcast.mybatis.pojo.User" />
        <!-- 批量別名定義,掃描整個(gè)包下的類,別名為類名(大小寫不敏感) -->
        <package name="cn.itcast.mybatis.pojo" />
        <package name="其它包" />
    </typeAliases>

    <!-- 和spring整合后 environments配置將廢除 -->
    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事務(wù)管理 -->
            <transactionManager type="JDBC" />
            <!-- 數(shù)據(jù)庫連接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>
    </environments>

    <!-- 加載映射文件 -->
    <mappers>
        <mapper resource="sqlmap/User.xml" />
        <mapper resource="mapper/UserMapper.xml" />
    </mappers>
</configuration>

在mapper.xml配置文件中,就可以使用設(shè)置的別名了
別名大小寫不敏感

圖片.png

mappers(映射器)

Mapper配置的幾種方法

  • <mapper resource=""/>
    使用相對(duì)于類路徑的資源(現(xiàn)在的使用方式)
<mapper resource="sqlmap/User.xml" />
  • <mapper class=""/> 使用mapper類接口路徑
<mapper class="cn.itcast.mybatis.mapper.UserMapper"/>

此方法要求mapper接口名稱和mapper映射文件名稱相同,且放在同一個(gè)目錄中

  • <package name=""/> 注冊(cè)指定包下的所有mapper接口
<package name="cn.probuing.xxx"/>

此方法要求mapper接口名稱和mapper映射文件名稱相同,且放在同一個(gè)目錄中

Mybatis輸入映射和輸出映射

輸出簡單類型

輸出POJO對(duì)象

開發(fā)中通過可以使用pojo傳遞查詢條件
查詢條件可能是綜合的查詢條件,不僅包括用戶的查詢條件還包括其它的查詢條件
包裝對(duì)象:Pojo類中的一個(gè)屬性是另外一個(gè)pojo

創(chuàng)建包裝類對(duì)象QueryVo

public class QueryVo {
    private User user;

    
    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
    
}

創(chuàng)建映射文件Mapper.xml文件

其中輸入?yún)?shù)為包裝條件對(duì)象QueryVo 輸出對(duì)象為User泛型

    <!--根據(jù)用戶名查詢數(shù)據(jù)-->
    <select id="selectListByUserNameQueryVo" parameterType="QueryVo" resultType="cn.probuing.mybatisintro.pojo.User">
        SELECT * FROM user where username LIKE  '%${user.username}'
    </select>

Mapper接口

在UserMapper接口中添加方法

   /**
     * 根據(jù)包裝條件查詢用戶列表數(shù)據(jù)
     *
     * @param queryVo
     * @return
     */
    public List<User> queryUserByQueryVo(QueryVo queryVo);

測試方法

    @Test
    public void testQueryVo() throws IOException {
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = builder.build(Resources.getResourceAsStream("SqlMapConfig.xml"));
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        QueryVo queryVo = new QueryVo();
        User user = new User();
        user.setUsername("五");
        queryVo.setUser(user);
        List<User> list = userMapper.selectListByUserNameQueryVo(queryVo);
        for (User user1 : list) {
            System.out.println(user1);
        }
    }

resultMap

在Mapper文件中,resultType可以指定將查詢結(jié)果映射為POJO,前提必須是POJO和sql查詢的列名一致方可映射成功。
如果sql查詢字段名和POJO的屬性名不一致,可以通過resultMap將字段名和屬性名作為一個(gè)指定的對(duì)應(yīng)關(guān)系。resultMap實(shí)質(zhì)上還需要將查詢結(jié)果映射到POJO對(duì)象中。
resultMap可以實(shí)現(xiàn)將查詢結(jié)果映射為復(fù)雜類型的POJO

創(chuàng)建一個(gè)POJO

package cn.probuing.mybatisintro.pojo;

import java.io.Serializable;
import java.util.Date;

public class Orders  implements Serializable{
    @Override
    public String toString() {
        return "Orders [id=" + id + ", userId=" + userId + ", number=" + number + ", createtime=" + createtime
                + ", note=" + note + "]";
    }

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private Integer id;

    private Integer userId;

    private String number;

    private Date createtime;

    private String note;
    
    //附加對(duì)象  用戶對(duì)象
    private User user;
    
    
    
    
    

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public Integer getId() {
        return id;
    }

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

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number == null ? null : number.trim();
    }

    public Date getCreatetime() {
        return createtime;
    }

    public void setCreatetime(Date createtime) {
        this.createtime = createtime;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note == null ? null : note.trim();
    }

    
    
}

該pojo中 order中的userid與數(shù)據(jù)庫中表對(duì)應(yīng)的查詢列不一致

創(chuàng)建OrderMapper.xml映射文件

<mapper namespace="cn.probuing.mybatisintro.mapper.OrderMapper">

    <!--
        id 對(duì)應(yīng)指定的resultMap標(biāo)識(shí)
        type 指定映射到哪一個(gè)pojo上
    -->
    <resultMap id="orderResultMap" type="orders">
        <!--id 定義主鍵 如果是多個(gè)字段 則定義多個(gè)id
        標(biāo)簽中的property 表示 指定映射到pojo的哪個(gè)屬性
        標(biāo)簽中的column 表示 指定映射到數(shù)據(jù)庫中的列名
        -->
        <id property="id" column="id"/>
        <!--普通屬性使用result定義-->
        <result property="userId" column="user_id"/>
        <result property="number" column="number"/>
        <result property="createtime" column="createtime"/>
        <result property="note" column="note"/>
    </resultMap>
    <!--resultMap標(biāo)簽指定一個(gè)ResultMap的標(biāo)識(shí)-->
    <select id="queryOrderList" resultMap="orderResultMap">
        SELECT id, user_id,
        number,
        createtime, note FROM `orders`
    </select>

</mapper>

測試代碼

  @Test
    public void testResultMapQuery() throws IOException {
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = builder.build(Resources.getResourceAsStream("SqlMapConfig.xml"));
        SqlSession sqlSession = sqlSessionFactory.openSession();
        OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
        List<Orders> orderList = orderMapper.queryOrderList();
        for (Orders orders : orderList) {
            System.out.println(orders);
        }
    }

動(dòng)態(tài)SQL

通過Mybatis提供的各種標(biāo)簽方法實(shí)現(xiàn)動(dòng)態(tài)拼接SQL

if標(biāo)簽

編寫mapper.xml文件

  <!--動(dòng)態(tài)標(biāo)簽-->
    <select id="queryUserByWhere" parameterType="user" resultType="user">
        <!-- 考慮到sex 和username不一定同時(shí)存在 所以加入if標(biāo)簽進(jìn)行判斷 -->
        SELECT * FROM user
        WHERE 1=1
        <if test="sex !=null and sex !=''">
            and sex = #{sex}
        </if>
        <if test="username !=null and username !=''">
            and username LIKE "%${username}%"
        </if>
    </select>

上面這種判斷 還是存在where 1=1 的情況,這種情況顯然還是很麻煩的 ,下面我們使用where標(biāo)簽對(duì)上面的判斷進(jìn)行改造

where標(biāo)簽

mapper.xml文件

 <select id="queryUserByWhere" parameterType="user" resultType="user">
        <!-- 考慮到sex 和username不一定同時(shí)存在 所以加入if標(biāo)簽進(jìn)行判斷 -->
        SELECT * FROM user
        <where>

            <if test="sex !=null and sex !=''">
                and sex = #{sex}
            </if>
            <if test="username !=null and username !=''">
                and username LIKE "%${username}%"
            </if>
        </where>

    </select>

where標(biāo)簽會(huì)自動(dòng)添加where條件,同時(shí)會(huì)處理sql語句中的第一個(gè)and關(guān)鍵字

sql片段

sql中可將重復(fù)的sql提取出來,使用時(shí)用Include引用,最終達(dá)到sql重用的目的
上面的sql提取出來后

 <!-- 根據(jù)條件查詢用戶 -->
<select id="queryUserByWhere" parameterType="user" resultType="user">
    <!-- SELECT id, username, birthday, sex, address FROM `user` -->
    <!-- 使用include標(biāo)簽加載sql片段;refid是sql片段id -->
    SELECT <include refid="userFields" /> FROM `user`
    <!-- where標(biāo)簽可以自動(dòng)添加where關(guān)鍵字,同時(shí)處理sql語句中第一個(gè)and關(guān)鍵字 -->
    <where>
        <if test="sex != null">
            AND sex = #{sex}
        </if>
        <if test="username != null and username != ''">
            AND username LIKE
            '%${username}%'
        </if>
    </where>
</select>

<!-- 聲明sql片段 -->
<sql id="userFields">
    id, username, birthday, sex, address
</sql>

foreach標(biāo)簽

向sql中傳遞數(shù)組或list mybatis使用foreach解析

改造QueryVo

在QueryVo中加入List代表多個(gè)id的集合

public class QueryVo implements Serializable {
    private User user;
    private List<Integer> ids;

    public List<Integer> getIds() {
        return ids;
    }

    public void setIds(List<Integer> ids) {
        this.ids = ids;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

}

Mapper.xml文件

 <!--根據(jù)ids查詢用戶-->
    <select id="queryUserByIds" parameterType="queryVo" resultType="user">
        SELECT * FROM user
        <where>
            <!--
             foreach標(biāo)簽
             collection:要遍歷的集合,在這里是QueryVo中的ids屬性 
             直接傳遞數(shù)組時(shí)collection指定array
              直接傳遞list時(shí)collection指定list
              




             item:遍歷的項(xiàng)目
             open:在前面添加的sql片段
             close:在結(jié)尾處添加的sql片段
             separator:指定遍歷的元素之間使用的分隔符
             -->
            <foreach collection="ids" item="item" open="id in (" close=")" separator=",">
                #{item}
            </foreach>
        </where>
    </select>

測試方法

   @Test
    public void testQueryByIds() throws IOException {
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = builder.build(Resources.getResourceAsStream("SqlMapConfig.xml"));
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        QueryVo queryVo = new QueryVo();
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(10);
        list.add(24);
        queryVo.setIds(list);
        List<User> users = userMapper.queryUserByIds(queryVo);
        for (User user : users) {
            System.out.println(user);
        }
    }

一對(duì)一查詢

使用resultMap

改造pojo類

在Order類中加入U(xiǎn)ser屬性,user屬性中用于存儲(chǔ)關(guān)聯(lián)查詢的用戶信息,對(duì)于訂單來說訂單關(guān)聯(lián)查詢用戶是一對(duì)一關(guān)系,所以這里使用單個(gè)User對(duì)象存儲(chǔ)關(guān)聯(lián)查詢的用戶信息

public class Orders  implements Serializable{
    @Override
    public String toString() {
        return "Orders [id=" + id + ", userId=" + userId + ", number=" + number + ", createtime=" + createtime
                + ", note=" + note + "]";
    }

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private Integer id;

    private Integer userId;

    private String number;

    private Date createtime;

    private String note;
    
    //附加對(duì)象  用戶對(duì)象
    private User user;
}

Mapper.xml

  <resultMap id="orderUserResultMap" type="orders">
        <!--映射數(shù)據(jù)庫主鍵 id-->
        <id property="id" column="id"/>
        <result property="userId" column="user_id"/>
        <result property="number" column="number"/>
        <result property="createtime" column="createtime"/>
        <result property="note" column="note"/>
        <!--一對(duì)一屬性映射-->
        <association property="user" javaType="user">
            <id property="id" column="user_id"/>
            <result property="username" column="username"/>
            <result property="address" column="address"/>
        </association>
    </resultMap>
    <!--一對(duì)一關(guān)聯(lián),查詢訂單,訂單內(nèi)部包含用戶屬性-->
    <select id="queryOrderUserResultMap" resultMap="orderUserResultMap">
        SELECT
            o.id,
            o.user_id,
            o.number,
            o.createtime,
            o.note,
            u.username,
            u.address
        FROM
            `orders` o
            LEFT JOIN `user` u ON o.user_id = u.id
    </select>

上面的配置文件中 左關(guān)聯(lián)查詢時(shí) 對(duì)應(yīng)映射的類與數(shù)據(jù)庫查詢列不一致 所以使用resultMap映射
Orders中有User屬性,所以需要使用一對(duì)一映射User 使用resultMap的association標(biāo)簽映射User屬性,在association標(biāo)簽下 再分別映射user對(duì)象的屬性 其中指定的property是user對(duì)象的屬性名 column是對(duì)應(yīng)數(shù)據(jù)庫列的名稱

測試代碼

 @Test
    public void testQueryByResultMap() throws IOException {
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = builder.build(Resources.getResourceAsStream("SqlMapConfig.xml"));
        SqlSession sqlSession = sqlSessionFactory.openSession();
        OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
        List<Orders> orders = orderMapper.queryOrderUserResultMap();
        for (Orders order : orders) {
            System.out.println(order);
        }
    }

一對(duì)多查詢

修改POJO User類

public class User implements Serializable {
    /**
     *
     */
    private static final long serialVersionUID = 1L;
    private Integer id;
    private String username;// 用戶姓名
    private String sex;// 性別
    private Date birthday;// 生日
    private String address;// 地址

    private List<Orders> ordersList;

    public List<Orders> getOrdersList() {
        return ordersList;
    }

    public void setOrdersList(List<Orders> ordersList) {
        this.ordersList = ordersList;
    }
}

Mapper.xml 映射文件

  <resultMap type="User" id="user">
        <id column="id" property="id"/>
        <result column="username" property="username"/>
        <!-- 一對(duì)多 -->
        <collection property="orders" ofType="Orders">
            <id column="id" property="id"/>
            <result column="user_id" property="userId"/>
            <result column="number" property="number"/>
        </collection>
    </resultMap>
    <select id="queryUserOrder" resultMap="user">
        SELECT
            o.id,
            o.user_id,
            o.number,
            o.createtime,
            u.username
        FROM user u
            left join orders o
                on o.user_id = u.id
    </select>

Mybatis整合Spring

整合思路

  • SqlSessionFactory對(duì)象應(yīng)該放到spring容器中作為單例存在。
  • 傳統(tǒng)dao的開發(fā)方式中,應(yīng)該從spring容器中獲得sqlsession對(duì)象。
  • Mapper代理形式中,應(yīng)該從spring容器中直接獲得mapper的代理對(duì)象。
  • 數(shù)據(jù)庫的連接以及數(shù)據(jù)庫連接池事務(wù)管理都交給spring容器來完成。

整合需要的jar包

spring的jar包
Mybatis的jar包
Spring+mybatis的整合包。
Mysql的數(shù)據(jù)庫驅(qū)動(dòng)jar包。
數(shù)據(jù)庫連接池的jar包。

SqlMapConfig.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>
    <!-- 設(shè)置別名 -->
    <typeAliases>
        <!-- 2. 指定掃描包,會(huì)把包內(nèi)所有的類都設(shè)置別名,別名的名稱就是類名,大小寫不敏感 -->
        <package name="cn.probuing.mybatisspring.pojo"/>
    </typeAliases>

</configuration>

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <!--加載配置文件-->
    <context:property-placeholder location="classpath:config/db.properties"/>
    <!--配置數(shù)據(jù)庫連接池-->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>

    </bean>
    <!--配置sqlsessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--配置mybatis核心配置文件-->
        <property name="configLocation" value="classpath:config/SqlMapConfig.xml"/>
        <!--配置數(shù)據(jù)源-->
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--配置UserMapper-->
    <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <!--配置mapper接口-->
        <property name="mapperInterface" value="cn.probuing.mybatisspring.mapper.UserMapper"/>
        <!--配置SqlSessionFactory工廠-->
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>
</beans>

db.properties

Mapper接口

public interface UserMapper {
    public User findUserById(Integer id);
}

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="cn.probuing.mybatisspring.mapper.UserMapper">
    <select id="findUserById" parameterType="Integer" resultType="User">
        SELECT *
        FROM user
        where id = #{v}
    </select>
</mapper>

測試代碼

  @Test
    public void testQueryById() {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("config/applicationContext.xml");
        UserMapper userMapper = (UserMapper) applicationContext.getBean("userMapper");
        User user = userMapper.findUserById(10);
        System.out.println(user);
    }

在存在多個(gè)mapper的時(shí)候 在spring中都需要制定具體的mapper 這種方式在我們開發(fā)中是很麻煩的,所以在這種時(shí)候我們引入掃描包形式配置mapper

掃描包形式配置mapper

在配置的時(shí)候需要制定 MapperScannerConfigurer 在property中指定掃描的基礎(chǔ)包
由于工廠已經(jīng)實(shí)例化 所以不需要指定工廠 MapperScannerConfigurer也能找到工廠

    <!--包掃描形式配置mapper-->
    <bean  class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="cn.probuing.mybatisspring.mapper"/>
    </bean>

Mybatis逆向工程

使用官方網(wǎng)站提供的Mapper自動(dòng)生成工具 mybatis-generator-core來生成pojo類和Mapper映射文件

導(dǎo)入逆向工程

官方提供的逆向工程

修改配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
  PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <context id="testTables" targetRuntime="MyBatis3">
        <commentGenerator>
            <!-- 是否去除自動(dòng)生成的注釋 true:是 : false:否 -->
            <property name="suppressAllComments" value="true" />
        </commentGenerator>
        <!--數(shù)據(jù)庫連接的信息:驅(qū)動(dòng)類、連接地址、用戶名、密碼 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
            connectionURL="jdbc:mysql://localhost:3306/mybatis" userId="root" password="root">
        </jdbcConnection>
        <!-- <jdbcConnection driverClass="oracle.jdbc.OracleDriver" connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:yycg" 
            userId="yycg" password="yycg"> </jdbcConnection> -->

        <!-- 默認(rèn)false,把JDBC DECIMAL 和 NUMERIC 類型解析為 Integer,為 true時(shí)把JDBC DECIMAL 
            和 NUMERIC 類型解析為java.math.BigDecimal -->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>

        <!-- targetProject:生成PO類的位置 -->
        <javaModelGenerator targetPackage="cn.itcast.ssm.po"
            targetProject=".\src">
            <!-- enableSubPackages:是否讓schema作為包的后綴 -->
            <property name="enableSubPackages" value="false" />
            <!-- 從數(shù)據(jù)庫返回的值被清理前后的空格 -->
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!-- targetProject:mapper映射文件生成的位置 -->
        <sqlMapGenerator targetPackage="cn.itcast.ssm.mapper"
            targetProject=".\src">
            <!-- enableSubPackages:是否讓schema作為包的后綴 -->
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>
        <!-- targetPackage:mapper接口生成的位置 -->
        <javaClientGenerator type="XMLMAPPER"
            targetPackage="cn.itcast.ssm.mapper" targetProject=".\src">
            <!-- enableSubPackages:是否讓schema作為包的后綴 -->
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>
        <!-- 指定數(shù)據(jù)庫表 -->
        <table schema="" tableName="user"></table>
        <table schema="" tableName="order"></table>
    </context>
</generatorConfiguration>

生成逆向工程代碼 執(zhí)行工程main主函數(shù)

圖片.png

圖片.png

代碼生成在工程目錄下

圖片.png

注意

  • 逆向工程生成的代碼只能做單表查詢
  • 不能在生成的代碼上進(jìn)行擴(kuò)展,因?yàn)槿绻麛?shù)據(jù)庫變更,需要重新使用逆向工程生成代碼,原來編寫的代碼就被覆蓋了。
  • 一張表會(huì)生成4個(gè)文件
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容