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

Mybatis介紹

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

JDBC存在的問題

1贮预、 數(shù)據(jù)庫連接創(chuàng)建、釋放頻繁造成系統(tǒng)資源浪費,從而影響系統(tǒng)性能仿吞。如果使用數(shù)據(jù)庫連接池可解決此問題滑频。
2、 Sql語句在代碼中硬編碼唤冈,造成代碼不易維護峡迷,實際應用中sql變化的可能較大,sql變動需要改變java代碼你虹。
3绘搞、 使用preparedStatement向占有位符號傳參數(shù)存在硬編碼,因為sql語句的where條件不一定傅物,可能多也可能少夯辖,修改sql還要修改代碼,系統(tǒng)不易維護董饰。
4楼雹、 對結果集解析存在硬編碼(查詢列名),sql變化導致解析代碼變化尖阔,系統(tǒng)不易維護贮缅,如果能將數(shù)據(jù)庫記錄封裝成pojo對象解析比較方便。

Mybatis架構

Mybatis架構

Mybatis使用

mybaits的代碼由github.com管理

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

mybatis如下:


圖片.png

目錄結構

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

創(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事務管理 -->
            <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>

標簽解釋

在pojo的映射文件xml中介却,包含<select>谴供、<insert>、<update>齿坷、<delete> 分別對應 查詢桂肌、添加、更新永淌、刪除操作

  • 其中 id 代表對應標簽的識別id
  • parameterType代表占位符的類型
  • resultType 代表返回值類型

語句解釋

#{v}代表占位符 占位符標識為v
${value}代表字符串拼接 標識必須為value

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

        //加載SqlMapConfig.xml配置文件 創(chuàng)建SqlSessionFactory
        SqlSessionFactory sessionFactory = builder.build(Resources.getResourceAsStream("SqlMapConfig.xml"));
        //創(chuàng)建SqlSession對象
        SqlSession sqlSession = sessionFactory.openSession();
        //SqlSession執(zhí)行對象查詢
        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)資源浪費從而影響系統(tǒng)性能遂蛀,如果使用數(shù)據(jù)庫連接池可解決此問題谭跨。
解決:在SqlMapConfig.xml中配置數(shù)據(jù)連接池,使用連接池管理數(shù)據(jù)庫鏈接李滴。
2螃宙、Sql語句寫在代碼中造成代碼不易維護,實際應用sql變化的可能較大所坯,sql變動需要改變java代碼谆扎。
解決:將Sql語句配置在XXXXmapper.xml文件中與java代碼分離。
3芹助、向sql語句傳參數(shù)麻煩堂湖,因為sql語句的where條件不一定闲先,可能多也可能少,占位符需要和參數(shù)一一對應无蜂。
解決:Mybatis自動將java對象映射至sql語句伺糠,通過statement中的parameterType定義輸入?yún)?shù)的類型。
4酱讶、對結果集解析麻煩退盯,sql變化導致解析代碼變化彼乌,且解析前需要遍歷泻肯,如果能將數(shù)據(jù)庫記錄封裝成pojo對象解析比較方便。
解決:Mybatis自動將sql執(zhí)行結果映射至java對象慰照,通過statement中的resultType定義輸出結果的類型

提出一個需求

MyBatis與HIbernate的不同

Mybatis和hibernate不同灶挟,它不完全是一個ORM框架,因為MyBatis需要程序員自己編寫Sql語句毒租。mybatis可以通過XML或注解方式靈活配置要運行的sql語句稚铣,并將java對象和sql語句映射生成最終執(zhí)行的sql,最后將sql執(zhí)行的結果再映射生成java對象墅垮。

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

Hibernate對象/關系映射能力強,數(shù)據(jù)庫無關性好鲫忍,對于關系模型要求高的軟件(例如需求固定的定制化軟件)如果用hibernate開發(fā)可以節(jié)省很多代碼毛俏,提高效率。但是Hibernate的學習門檻高饲窿,要精通門檻更高煌寇,而且怎么設計O/R映射,在性能和對象模型之間如何權衡逾雄,以及怎樣用好Hibernate需要具有很強的經(jīng)驗和能力才行阀溶。
總之腻脏,按照用戶的需求在有限的資源環(huán)境下只要能做出維護性、擴展性良好的軟件架構都是好架構银锻,所以框架只有適合才是最好永品。

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

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

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

  • 1、 Mapper.xml文件中的namespace與mapper接口的類路徑相同更振。
  • 2炕桨、Mapper接口方法名和Mapper.xml中定義的每個statement的id相同
  • 3、Mapper接口方法的輸入?yún)?shù)類型和mapper.xml中定義的每個sql 的parameterType的類型相同
  • 4肯腕、Mapper接口方法的輸出參數(shù)類型和mapper.xml中定義的每個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(對象工廠)
  • plugins(插件)
  • environments(環(huán)境集合屬性對象)
    • environment(環(huán)境子屬性對象)
      • transactionManager(事務管理)
      • 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事務管理 -->
            <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)定義的屬性首先被讀取
  • 然后會讀取properties元素中resource或url加載的屬性,它會覆蓋已讀取的同名屬性

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

    <!-- 和spring整合后 environments配置將廢除 -->
    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事務管理 -->
            <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配置文件中憾赁,就可以使用設置的別名了
別名大小寫不敏感

圖片.png

mappers(映射器)

Mapper配置的幾種方法

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

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

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

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

Mybatis輸入映射和輸出映射

輸出簡單類型

輸出POJO對象

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

創(chuàng)建包裝類對象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ù)為包裝條件對象QueryVo 輸出對象為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可以指定將查詢結果映射為POJO或颊,前提必須是POJO和sql查詢的列名一致方可映射成功咨油。
如果sql查詢字段名和POJO的屬性名不一致,可以通過resultMap將字段名和屬性名作為一個指定的對應關系原在。resultMap實質上還需要將查詢結果映射到POJO對象中友扰。
resultMap可以實現(xiàn)將查詢結果映射為復雜類型的POJO

創(chuàng)建一個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;
    
    //附加對象  用戶對象
    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ù)庫中表對應的查詢列不一致

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

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

    <!--
        id 對應指定的resultMap標識
        type 指定映射到哪一個pojo上
    -->
    <resultMap id="orderResultMap" type="orders">
        <!--id 定義主鍵 如果是多個字段 則定義多個id
        標簽中的property 表示 指定映射到pojo的哪個屬性
        標簽中的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標簽指定一個ResultMap的標識-->
    <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);
        }
    }

動態(tài)SQL

通過Mybatis提供的各種標簽方法實現(xiàn)動態(tài)拼接SQL

if標簽

編寫mapper.xml文件

  <!--動態(tài)標簽-->
    <select id="queryUserByWhere" parameterType="user" resultType="user">
        <!-- 考慮到sex 和username不一定同時存在 所以加入if標簽進行判斷 -->
        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標簽對上面的判斷進行改造

where標簽

mapper.xml文件

 <select id="queryUserByWhere" parameterType="user" resultType="user">
        <!-- 考慮到sex 和username不一定同時存在 所以加入if標簽進行判斷 -->
        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標簽會自動添加where條件村怪,同時會處理sql語句中的第一個and關鍵字

sql片段

sql中可將重復的sql提取出來,使用時用Include引用浮庐,最終達到sql重用的目的
上面的sql提取出來后

 <!-- 根據(jù)條件查詢用戶 -->
<select id="queryUserByWhere" parameterType="user" resultType="user">
    <!-- SELECT id, username, birthday, sex, address FROM `user` -->
    <!-- 使用include標簽加載sql片段甚负;refid是sql片段id -->
    SELECT <include refid="userFields" /> FROM `user`
    <!-- where標簽可以自動添加where關鍵字,同時處理sql語句中第一個and關鍵字 -->
    <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標簽

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

改造QueryVo

在QueryVo中加入List代表多個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標簽
             collection:要遍歷的集合审残,在這里是QueryVo中的ids屬性 
             直接傳遞數(shù)組時collection指定array
              直接傳遞list時collection指定list
              




             item:遍歷的項目
             open:在前面添加的sql片段
             close:在結尾處添加的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);
        }
    }

一對一查詢

使用resultMap

改造pojo類

在Order類中加入User屬性梭域,user屬性中用于存儲關聯(lián)查詢的用戶信息,對于訂單來說訂單關聯(lián)查詢用戶是一對一關系搅轿,所以這里使用單個User對象存儲關聯(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;
    
    //附加對象  用戶對象
    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"/>
        <!--一對一屬性映射-->
        <association property="user" javaType="user">
            <id property="id" column="user_id"/>
            <result property="username" column="username"/>
            <result property="address" column="address"/>
        </association>
    </resultMap>
    <!--一對一關聯(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>

上面的配置文件中 左關聯(lián)查詢時 對應映射的類與數(shù)據(jù)庫查詢列不一致 所以使用resultMap映射
Orders中有User屬性璧坟,所以需要使用一對一映射User 使用resultMap的association標簽映射User屬性既穆,在association標簽下 再分別映射user對象的屬性 其中指定的property是user對象的屬性名 column是對應數(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);
        }
    }

一對多查詢

修改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"/>
        <!-- 一對多 -->
        <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對象應該放到spring容器中作為單例存在赎懦。
  • 傳統(tǒng)dao的開發(fā)方式中,應該從spring容器中獲得sqlsession對象幻工。
  • Mapper代理形式中励两,應該從spring容器中直接獲得mapper的代理對象。
  • 數(shù)據(jù)庫的連接以及數(shù)據(jù)庫連接池事務管理都交給spring容器來完成囊颅。

整合需要的jar包

spring的jar包
Mybatis的jar包
Spring+mybatis的整合包当悔。
Mysql的數(shù)據(jù)庫驅動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>
    <!-- 設置別名 -->
    <typeAliases>
        <!-- 2. 指定掃描包盲憎,會把包內(nèi)所有的類都設置別名,別名的名稱就是類名奸鬓,大小寫不敏感 -->
        <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);
    }

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

掃描包形式配置mapper

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

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

Mybatis逆向工程

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

導入逆向工程

官方提供的逆向工程

修改配置文件

<?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>
            <!-- 是否去除自動生成的注釋 true:是 : false:否 -->
            <property name="suppressAllComments" value="true" />
        </commentGenerator>
        <!--數(shù)據(jù)庫連接的信息:驅動類掸读、連接地址串远、用戶名、密碼 -->
        <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> -->

        <!-- 默認false儿惫,把JDBC DECIMAL 和 NUMERIC 類型解析為 Integer澡罚,為 true時把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

注意

  • 逆向工程生成的代碼只能做單表查詢
  • 不能在生成的代碼上進行擴展,因為如果數(shù)據(jù)庫變更肾请,需要重新使用逆向工程生成代碼留搔,原來編寫的代碼就被覆蓋了。
  • 一張表會生成4個文件
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末铛铁,一起剝皮案震驚了整個濱河市隔显,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌饵逐,老刑警劉巖括眠,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異倍权,居然都是意外死亡掷豺,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門薄声,熙熙樓的掌柜王于貴愁眉苦臉地迎上來当船,“玉大人,你說我怎么就攤上這事默辨〉缕担” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵缩幸,是天一觀的道長壹置。 經(jīng)常有香客問我档叔,道長,這世上最難降的妖魔是什么蒸绩? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任衙四,我火速辦了婚禮,結果婚禮上患亿,老公的妹妹穿的比我還像新娘传蹈。我一直安慰自己,他們只是感情好步藕,可當我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布惦界。 她就那樣靜靜地躺著,像睡著了一般咙冗。 火紅的嫁衣襯著肌膚如雪沾歪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天雾消,我揣著相機與錄音灾搏,去河邊找鬼。 笑死立润,一個胖子當著我的面吹牛狂窑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播桑腮,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼泉哈,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了破讨?” 一聲冷哼從身側響起丛晦,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎提陶,沒想到半個月后烫沙,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡搁骑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年斧吐,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片仲器。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡煤率,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出乏冀,到底是詐尸還是另有隱情蝶糯,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布辆沦,位于F島的核電站昼捍,受9級特大地震影響识虚,放射性物質發(fā)生泄漏。R本人自食惡果不足惜妒茬,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一担锤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧乍钻,春花似錦肛循、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至浩考,卻和暖如春夹孔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背析孽。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工搭伤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人绿淋。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓闷畸,卻偏偏與公主長得像尝盼,于是被迫代替她去往敵國和親吞滞。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容