Mybatis 學(xué)習(xí)

基礎(chǔ)知識學(xué)習(xí)

框架:開發(fā)中說的框架坦康,通常是一種解決方案胖秒,其內(nèi)部封裝了一些細(xì)節(jié)雷厂,使開發(fā)者可以通過很少的時間實現(xiàn)功能,提高開發(fā)效率奸忽。

三層架構(gòu)

? 表現(xiàn)層:用于展示數(shù)據(jù)堕伪。

? 業(yè)務(wù)層:用于處理業(yè)務(wù)需求,我們自己編碼實現(xiàn)栗菜。

? 持久層:用于與數(shù)據(jù)庫交互欠雌。

由于Mybatis是關(guān)于持久層的,后面就專注于持久層的知識疙筹。

持久層技術(shù)解決方案

  • JDBC技術(shù):是jdk官方提供的數(shù)據(jù)庫交互規(guī)范富俄。
  • Spring中的JdbcTemplate:是spring提供的數(shù)據(jù)庫交互工具,其在JDBC上進(jìn)行了簡單封裝
  • Apache的DButils:與JdbcTemplate相似而咆,也是實現(xiàn)了簡單封裝霍比。

說明:上述三者都并非框架。JDBC是一套規(guī)范翘盖,后兩者是該規(guī)范的簡單實現(xiàn)。他們都只是工具凹蜂,因為其并沒有形成一套完整的解決方案馍驯,我們在開發(fā)中仍需要做很多事。

myBatis概述

? mybatis是一個優(yōu)秀的基于java 的持久層框架玛痊,其內(nèi)部封裝了jdbc汰瘫,使開發(fā)者只需要關(guān)注sql語句本身,而不用花費(fèi)精力去處理加載驅(qū)動擂煞、創(chuàng)建連接混弥、創(chuàng)建statement等繁雜過程。

? mybatis通過xml或注解的方式將要執(zhí)行的各種statement配置起來,并通過java對象和statement中的sql的動態(tài)參數(shù)進(jìn)行映射(如:Object.query("select * from tableName where id=?",db.getId()))蝗拿,生成最終的sql語句晾捏,最后由mybatis框架執(zhí)行sql并將結(jié)果映射為java對象并返回。

? 采用思想:ORM(Object Relational Mapping哀托,對象關(guān)聯(lián)映射)惦辛,其解決了實體對象到數(shù)據(jù)庫表中的映射問題。對jdbc進(jìn)行了封裝仓手,屏蔽了jdbc api底層訪問的細(xì)節(jié)胖齐,使開發(fā)者無需與其打交道,就可以完成數(shù)據(jù)庫持久化操作嗽冒。


Mybatis環(huán)境搭建

小細(xì)節(jié)${}#{}的區(qū)別:效果都是占位呀伙,然后等待編譯時進(jìn)行變量替換。區(qū)別在于#{}替換后添坊,會加上引號剿另,表明該值是字符串;而${}替換后是不加字符串的帅腌,可以用于properties文件的引用驰弄、sql語句中如ORDER BY ${}等。

注意:當(dāng)使用${}作為sql語句時速客,內(nèi)部是固定占位符:${value}戚篙。

大致開發(fā)步驟

  • 1.建立maven工程并導(dǎo)入依賴
  • 2.創(chuàng)建實體類和dao的接口
  • 3.創(chuàng)建Mybatis的主配置文件:sqlMapConfig.xml
  • 4.創(chuàng)建每個dao對應(yīng)的映射配置文件:SubjectsDAOInterface.xml

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>
    <!-- 配置mybatis的主配置文件 -->
    <environments default="mysql">
        <!-- 配置mysql的環(huán)境 -->
        <environment id="mysql">
            <!-- 配置事務(wù)管理器 -->
            <transactionManager type="JDBC">
                <property name="dataSource" value="dataSource"/>
            </transactionManager>
            <!-- 配置數(shù)據(jù)源 -->
            <dataSource type="POOLED">
                <!-- 配置連接池的基本信息 -->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/TestBase"/>
                <property name="username" value="sun"/>
                <property name="password" value="sunlin"/>
            </dataSource>
        </environment>
    </environments>
    
    <!-- 指定映射配置文件的位置,其代表每個dao獨立的配置文件溺职;【注意resource的值是用'/’標(biāo)識目錄父子關(guān)系岔擂,而非‘.’來標(biāo)識!】 -->
    <mappers>
        <mapper resource="com/yinghuo/mybatisStudy/dao/SubjectsDAOInterface.xml"/>
    </mappers>
</configuration>

SubjectDAOInterface.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yinghuo.mybatisStudy.dao.SubjectsDAOInterface">
    <!-- 配置查詢 -->
    <select id="findAllSubjects">
        select * from subjects;
    </select>
</mapper>

注意事項

  • mybatis中浪耘,DAO的含義與Mapper相同乱灵。所以SubjectsDAO和SubjectMapper其意思相同,都代表實體類與數(shù)據(jù)庫的交互七冲。
  • mybatis的映射配置文件痛倚,如上面代碼SubjectDAOInterface.xml必須與dao接口的包結(jié)構(gòu)相同。(mybatis的映射配置文件在resources文件夾下澜躺,但其包結(jié)構(gòu)也跟SubjectDAOInterface一樣蝉稳。)
  • 映射配置文件SubjectDAOInterface.xml中,<mapper>標(biāo)簽的屬性namespace的取值必須為對應(yīng)dao接口的全限定名掘鄙。
  • 映射配置文件中耘戚,<mapper>中的子標(biāo)簽如:<select>,其id屬性必須為接口的方法名操漠。

有了上述四條事項中的后三條收津,我們就可以不用編寫dao接口的實現(xiàn)類了,mybatis會幫我們編寫。

dao功能的原始實現(xiàn)流程:

在一個類中的main函數(shù)體中:

public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        //1:獲取配置文件流
        //import org.apache.ibatis.io.Resources;
        InputStream in = Resources.getResourceAsStream("sqlMapConfig.xml");
        //2:創(chuàng)建SqlSessionFactory工廠
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        //3:用工廠創(chuàng)建SqlSession對象
        SqlSession ss = factory.openSession();
        //4:使用SqlSession對象創(chuàng)建dao接口的代理對象撞秋。
        SubjectsDAOInterface dao= ss.getMapper(SubjectsDAOInterface.class);
        //5:使用代理對象執(zhí)行方法
        List<Subjects> subjects = dao.findAllSubjects();
        for(Subjects s:subjects) {
            System.out.println(s);
        }
        //6:釋放資源
        ss.close();
        in.close();
    }

讀取配置文件說明:無論是主配置文件中的DataSource的屬性解析长捧、還是映射配置文件中的sql語句與dao接口方法關(guān)聯(lián)的解析,都是用到的一種解析方法:dom4j 解析xml技術(shù)

使用注解實現(xiàn)配置mapper:

? 用注解代替映射文件部服。

  • 主配置文件中:(得到dao接口類的全限定名)

    • <mappers>中的<mapper resource="">子標(biāo)簽的屬性改成<mapper class=""唆姐,class里面是全限定名,包以'.'分隔廓八。
  • dao接口代碼中:(得到該接口類的方法名)

    • 增加注釋:

      類中奉芦,方法前加:@Select("sql statement")

  • 編寫@Select注釋:(這步是自定義mybatis用到的

    • 首先設(shè)置該注釋的生命周期和作用對象:

      注釋體前加:@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)

    • 然后在注釋體內(nèi)剧蹂,設(shè)置一個字符串接收sql語句(在dao接口方法前注釋的@Select的值)

      String value();

mybatis實現(xiàn)思路:

自定義實現(xiàn)的項目:ubuntu--eclipse--mybatisCustom声功。

大體實現(xiàn)方法:

  • 1.通過xml解析工具,**解析主配置文件 **得到:
    • 連接所需參數(shù)信息
    • 映射配置文件(xml實現(xiàn)映射關(guān)聯(lián))
    • dao接口全限定類名(注解實現(xiàn)映射關(guān)聯(lián))
  • 2.在通過xml解析工具宠叼,解析映射配置文件或dao接口全限定名先巴,得到:
    • 被代理方法的全限定名
    • sql statement(語句)
    • 承載類的全限定名(用于和數(shù)據(jù)庫字段相對應(yīng)的那個實體類)
  • 3.經(jīng)第2步,已經(jīng)得到了所有信息冒冬,然后是要實現(xiàn)動態(tài)代理和反射調(diào)用了(自定義一個實現(xiàn)了InvacationHandler的處理類伸蚯,然后調(diào)用Proxy)。(這一步最麻煩简烤,我沒有成功剂邮,明明代碼都一樣,但是在invoke這一步横侦,說參數(shù)類型不匹配挥萌,但是明明是匹配的。)
    • 建立連接Connection
    • 建立預(yù)處理語句枉侧,并發(fā)送執(zhí)行引瀑。
    • 得到結(jié)果集,將結(jié)果集映射到承載類榨馁。
    • 返回代理對象憨栽。
1.jpg
2.jpg

mybatis 基礎(chǔ)的CRUD

操作基本與前述類似。

如下翼虫,是配置映射文件:實現(xiàn)了基本的增查改刪操作屑柔。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yinghuo.mybatisCRUD.dao.SubjectDAOInterface">

    <select id="findAll" resultType="com.yinghuo.mybatisCRUD.subject.Subjects">
        select * from subjects;
    </select>
    
    <select id="findOneById" resultType="com.yinghuo.mybatisCRUD.subject.Subjects" parameterType="INT">
        select * from subjects where id = #{id};
    </select>
    
    
    <insert id="saveOne" parameterType="com.yinghuo.mybatisCRUD.subject.Subjects">
        <!-- 保存后會反射,將當(dāng)前數(shù)據(jù)庫中id的值蛙讥,映射到實體類的對應(yīng)屬性锯蛀,若不加灭衷,則不會反射次慢,id若沒有初始化則為0 -->
        <selectKey keyProperty="id" keyColumn="id" resultType="INT" order="AFTER">
            select last_insert_id();
        </selectKey>
        INSERT into subjects(name,grade,enjoy) values(#{name},#{grade},#{enjoy});
    </insert>
    
    <delete id="deleteOneById" parameterType="java.lang.Integer">
        DELETE from subjects where id = #{id};
    </delete>
    
    <update id="updateOne" parameterType="com.yinghuo.mybatisCRUD.subject.Subjects">
        UPDATE subjects set name = #{name},grade=#{grade},enjoy=#{enjoy} where id=#{id}; 
    </update>
    
    <select id="findByName" resultType="com.yinghuo.mybatisCRUD.subject.Subjects" parameterType="String">
        select * from subjects where name like #{name};
    </select>
    
    <select id="findCounts" resultType="INT">
        select count(*) from subjects;
    </select>
</mapper>

標(biāo)簽

主配置文件中

注意:有順序要求,否則會報錯。如下依次迫像。

(properties, settings, typeAliases, typeHandlers, objectFactory, objectWrapperFactor, reflectorFactory, plugins, environments, databaseIdProvider, mappers)

  • <configuration>:主標(biāo)簽劈愚,必須要命名空間才能用:<!DOCTYPE Configuration...>。后面的標(biāo)簽都屬于本標(biāo)簽的子標(biāo)簽闻妓。

  • <environments>:用于包含多個配置環(huán)境菌羽。屬性:default,設(shè)置一個默認(rèn)的<environment>標(biāo)簽由缆。

  • <environment>:用于單個環(huán)境配置注祖。屬性:id,來標(biāo)識該環(huán)境配置標(biāo)簽均唉。

  • <transactionManager>:事務(wù)管理標(biāo)簽是晨。屬性:type,指定事務(wù)管理器類型舔箭,一般是jdbc

    • 子標(biāo)簽:<property>:用來注入成員變量dataSource罩缴。
  • <dataSource>:用來配置數(shù)據(jù)源。屬性:POOLED层扶,表示連接池箫章。

    • 子標(biāo)簽:多個<property>:用來配置連接信息:驅(qū)動、url镜会、用戶名檬寂、密碼。
  • <properties>:用來指定外部properties文件稚叹。屬性:resource焰薄,表示文件位置。

  • <typeAliases:用于配置包下所有類的別名扒袖。在mybatis中塞茅,由于預(yù)先設(shè)置了別名,如resultType="int"可以寫成resulttype="INt"季率,并不區(qū)分大小寫野瘦。

    當(dāng)我們自己想這樣使用的,可以用該標(biāo)簽飒泻。

    • 子標(biāo)簽:<typeAlias>:用于給某個指定類添加別名鞭光。
    • 子標(biāo)簽:<package:(*常用)用于給整個包下的所有類添加別名。屬性:name="..."
      • 用處
      • ①用于給dao所在包在主配置文件添加別名泞遗,然后在映射配置文件中惰许,就可以使用別名進(jìn)行引用,而不用全限定名史辙。
      • ②可以在<mappers>標(biāo)簽中汹买,直接寫<package name="dao接口所在位置">佩伤,可以替代<mapper class="..."><mapper resource="/../../";
dao接口映射配置文件中:
  • <mapper>:主標(biāo)簽。屬性:namespace="path.to.daoInterface"晦毙。

  • <select>生巡、<insert><update>见妒、<delete>:用于標(biāo)識方法孤荣。

    屬性:

    • id="method"
    • resultMap="resultMap的id"
    • resultType
    • parameterType="該方法參數(shù)類型"
  • <resultMap>:用于映射復(fù)雜的返回結(jié)果,如該實體類中引用別的對象须揣,該實體類變量名與數(shù)據(jù)庫中字段名不同等盐股。

    子標(biāo)簽:

    • <id property="" column="">:用于主鍵映射。
    • <result property="" column="">:用于其他字段映射耻卡。
    • <association property="" javaType="">:用于一對一查詢遂庄。
    • <collection property="" ofType="">:用于一對多查詢。

屬性:

  • id:辨識唯一標(biāo)簽

  • parameterType:當(dāng)dao接口的方法需要參數(shù)時劲赠,使用該屬性涛目。value=全限定類名或者可以標(biāo)識的名,如INT凛澎、int霹肝、string等

  • resultType:當(dāng)該方法需要返回值時,用這個來標(biāo)識返回值對象塑煎。value=全限定類名

OGNL表達(dá)式:(用于標(biāo)簽內(nèi)sql語句的參數(shù))

? Object Graphic Navigation Language沫换,對象圖導(dǎo)航語言。

? 作用:通過對象的取值方法來獲取數(shù)據(jù)最铁。(寫法上把get省略了)

? 類中寫法:user.getName();

? OGNL寫法:user.name

? mybatis寫法:name //因為在parameterType里面已經(jīng)提供了類型讯赏,所以省略了類。此處寫法的含 //義是在如<select ...>..here..</select>標(biāo)簽內(nèi)部的語句,如:#{name}

? 對象參數(shù):(通常用作對實體類對象的再包裝冷尉,開發(fā)中漱挎,由多個對象組成一個查詢條件類,來實現(xiàn)數(shù)據(jù)查 詢)

? 當(dāng)類對象作為方法參數(shù)時雀哨,若要用對象的成員變量的屬性磕谅,如Class Condition{ User user;}雾棺,傳入的 參數(shù)是Condition 對象膊夹,但要使用其中的user成員變量的屬性(成員變量)user.name。此時寫法為: #{user.name}

?

數(shù)據(jù)表字段與實體類屬性不同時:

當(dāng)數(shù)據(jù)庫的字段名和實體類的成員變量名不一樣時(當(dāng)然最好一樣)捌浩,可以使用兩種方式實現(xiàn)查詢結(jié)果正常映射到實體類:

  • sql語句中修改:在如:<select ...> select * from subjects</subject> (運(yùn)行效率更好)

    ? 對應(yīng)關(guān)系:id--myId放刨、name--myName、grade--myGrade

    ? 修改為:<select ...> select * id as myId,name as myName,grade as myGrade from

    ? subjects</subject>

  • 配置標(biāo)簽修改:可以通過<resultMap>標(biāo)簽修改:(開發(fā)效率稍高)

    <mapper>
      <resultMap id="subjectsMap" type="com.yinghuo.mybatis.subject.subjects">
          <!-- 主鍵修改 -->
          <id property="myId" column="id"/>
          <!-- 其余鍵修改 -->
          <result property="myName" column="name"/>
          <result property="myGrade" column="grade"/>
          <result property="myEnjoy" column="enjoy"/>
      </resultMap>
      
      <!-- 在對應(yīng)的查詢地方引用上面這個標(biāo)簽 -->
      <select id="findAll" resultMap="subjectsMap">
          select * from user;
      </select>
    <mapper>
    
配置properties文件

? 可以在resourese文件夾下創(chuàng)建properties文件尸饺,其中有多個值进统,每個值為{key拓诸、Value}映射形式:name=sun。

主配置.xml文件使用properties文件

? 配置:通過在 Configuration 主標(biāo)簽下添加 <properties>標(biāo)簽麻昼,然后寫 屬性resource=" ''。其指為相對地址馋辈,如果放在resource下抚芦,則直接寫文件名.properties。如:<properties resource="jdbcConfig.properties">

? 使用:然后在后面的子標(biāo)簽如<DataSource>中的子標(biāo)簽<property>迈螟,即可直接使用${key}來獲得properties文件中的value的值叉抡。


mybatis 連接池配置

三種配置方式

  • 主配置文件中的<dataSource>標(biāo)簽

    屬性type的取值:

    • ①POOLED :采用傳統(tǒng)的javax.sql.DataSource規(guī)范(接口)中的連接池,mybatis有對其的實現(xiàn)類答毫。

    • ②UNPOOLED :也是有實現(xiàn)了上述規(guī)范的實現(xiàn)類褥民,但是沒有連接池概念。連接是用時生成洗搂,關(guān)閉就真正銷毀了消返。

    • ③ JNDI :采用服務(wù)器提供的 JDNI 技術(shù)實現(xiàn),來獲取DataSource對象耘拇,不同服務(wù)器能拿到的DataSource不一樣撵颊。如 tomcat服務(wù)器采用dbcp連接池。

      注意:如果不是web或maven的war工廠惫叛,不能使用倡勇。

POOLED取連接過程:

概述:mybatis使用PooledDataSource 類來實現(xiàn) java 的DataSource 規(guī)范,其內(nèi)部步驟大概如下:

  • ①要新建連接時嘉涌,看空閑池里是否有連接妻熊,若有,則取出一個返回仑最。
  • ②若空閑池沒有連接扔役,則查看活躍池,若活躍池中連接數(shù)未達(dá)到最大數(shù)量警医,則新建一個連接厅目,并放入活躍池,并返回法严。
  • ③若活躍池已達(dá)到最大數(shù)量损敷,則從其中選擇最先進(jìn)來的(最老的)那個連接,進(jìn)行適當(dāng)加工深啤,并返回拗馒。

Sql語句和映射配置文件

說明:查詢語句有條件時,可以用配置文件中的標(biāo)簽進(jìn)行輔助完成溯街。

映射配置文件中:

下述都是在<select>標(biāo)簽的內(nèi)部:

  • <where>:用了該標(biāo)簽诱桂,可以省略sql語句中的where 1=1(當(dāng)多個與洋丐、或條件時),子標(biāo)簽<if>

  • <if>:屬性為:test="condition"挥等。用作條件語句友绝,當(dāng)不滿足條件時,該標(biāo)簽內(nèi)部的子標(biāo)簽和語句不會被執(zhí)行肝劲。注意迁客,條件語句中不能用&&、||辞槐,要用and掷漱、or代替

  • <foreach>:主要用于集合類型參數(shù),配合實體封裝類參數(shù)進(jìn)行使用榄檬。

    屬性:

    • collection:集合屬性名
    • open:一般為:and id in(
    • close:一般為:)
    • item:該屬性的值如:id卜范,與內(nèi)部相對應(yīng):#{id}。
    • separator:每個id中的分隔符:,

mybatis多表查詢

步驟

①mysql中建立兩個表(暫時以2代多)

②在項目中建立兩個實體類鹿榜、及其dao接口類

③配置兩個dao接口的映射文件

④測試海雪、實現(xiàn)配置

一對一:(包含多對一)

適用:①一對一對象;②一對多對象中舱殿,以”多“為主體喳魏,去包含唯一的“一”。

說明:通常是一對一的怀薛,如人和身份證刺彩。或者是用戶和銀行卡中枝恋,一張銀行卡只能對應(yīng)一個用戶创倔。

resultMap中標(biāo)簽:

  • <association>
    • 屬性:javaType:填寫類中引用對象的類型。

因為一對多焚碌,如一個study有多個subjects畦攘。但是一個subject只對應(yīng)一個study,所以可以放在一起

<resultMap type="Subjects" id="UserSubjectsMap">
    <id property="id" column="id" />
    <result property="uid" column="uid"/>
    <result property="name" column="name" />
    <result property="grade" column="grade" />
    <result property="enjoy" column="enjoy" />
    <association property="user" javaType="user">
        <result property="name" column="uName" />
        <result property="sex" column="sex" />
        <result property="address" column="address" />
        <result property="city" column="city" />
    </association>
</resultMap>

<select id="findAll" resultMap="UserSubjectsMap">
        select s.*,u.name as uName,u.sex,u.address,u.city from subjects s,user u where u.id=s.uid;
</select>

一對多:

說明:如一個學(xué)生十电,有多門學(xué)科成績知押。

resultMap中標(biāo)簽:

  • <collection>
    • 屬性:ofType:填寫集合中的元素類型,如list<E>中的E鹃骂。

dao映射配置文件

    <resultMap id="userSubjectsMap" type="user">
        <!-- 主鍵映射 -->
        <id property="id" column="userId"/>
        <!-- 其余鍵映射 -->
        <result property="name" column="uName"/>
        <result property="sex" column="sex"/>
        <result property="city" column="city"/>
        <result property="address" column="address"/>
        <!-- 用于映射集合對象台盯,像List -->
        <collection property="subs" ofType="Subjects">
            <id property="id" column="id"/>
            <result property="uid" column="uid"/>
            <result property="name" column="name"/>
            <result property="enjoy" column="enjoy"/>
            <result property="grade" column="grade"/>
        </collection>
    </resultMap>
    
    <select id="findAll" resultMap="userSubjectsMap">
        select u.id as userId,u.name as uName,s.*,u.sex,u.city,u.address from user u LEFT           JOIN subjects s on u.id=s.uid;
    </select>

注意:user是主表,subjects是從表畏线。

多對多

項目:ubuntu -- eclipse -- mybatisMany4Many

說明:如一個用戶静盅,其可以多個愛好。而多個人寝殴,可以有同一個愛好蒿叠。如此明垢,用戶庫和愛好庫則是多對多橄登。

sql語句:(兩表為例)

  • 首先需要一個中間表user-enjoy痛悯,其數(shù)據(jù)項為:另兩表的主鍵(如id)。
  • 然后是sql語句形如:Select u.*,e.* from user u Left outer join user-enjoy ue on u.id=ue.uid LEFT OUTER JOIN enjoy e on e.id=ue.eid;

注意:編寫sql語句中航邢,多次將最后的條件子句中施绎,別名寫成了原名溯革,這會報錯。

下述代碼:User 和 Role類粘姜,多對多查詢。Role的dao接口省略熔酷。

    <resultMap id="userRoleMap" type="user">
        <!-- 主鍵映射 -->
        <id property="id" column="id"/>
        <!-- 其余鍵映射 -->
        <result property="name" column="name"/>
        <result property="sex" column="sex"/>
        <result property="city" column="city"/>
        <result property="address" column="address"/>
        <!-- 用于映射集合對象孤紧,像List -->
        <collection property="roles" ofType="Role">
            <id property="roleId" column="roleId"/>
            <result property="roleName" column="roleName"/>
            <result property="roleDesc" column="roleDesc"/>
        </collection>
    </resultMap>
    
    <select id="findAll" resultMap="userRoleMap">
        select u.*,r.* from user u left join user_role ur on ur.userId=u.id LEFT join role r on r.roleId=ur.roleId;
    </select>
    
    <select id="findOneById" resultMap="userRoleMap" parameterType="INT">
        select u.*,ur.*,r.* from user u,user_role ur,role r where ur.userId=u.id and u.id=${int} and ur.roleId=r.roleId; 
    </select>

JNDI

? JNDI(Java Naming and Directory Interface,java命名和目錄接口)拒秘,是sun公司提供的一種標(biāo)準(zhǔn)的java命名系統(tǒng)接口号显。

? 說明:其打包方式為war(web archive),用于網(wǎng)頁應(yīng)用躺酒。具體還是要找專門資料


mybatis緩存

延遲加載

問題:在一對多中押蚤,當(dāng)我們有一個用戶,他有100個賬戶羹应,在查詢用戶的時候揽碘,要不要把關(guān)聯(lián)的賬戶查出來?查詢賬戶時园匹,要不要把關(guān)聯(lián)用戶查出來雳刺?

  • 查用戶時:應(yīng)該延遲加載,即真正使用賬戶數(shù)據(jù)是才加載裸违,不用的時候不查詢掖桦。延遲加載也叫按需加載或懶加載。
  • 查賬戶時:可以立即加載供汛。即不管用不用枪汪,只要一調(diào)用方法,馬上發(fā)起查詢怔昨。

四種表關(guān)系

一對多雀久、多對多:通常使用延遲加載。

一對一趁舀、多對一:通常使用立即加載岸啡。

實現(xiàn)方式:無論是一對多還是多對一,其實都類似赫编,就是在<resultMap>中的<association><collection>中巡蘸,引用其他映射配置文件的<select>語句奋隶。

X對一:

步驟:

  • 首先,兩個實體類已經(jīng)有了悦荒,并且類中包含了對方的引用(成員變量)唯欣。

  • 然后,dao接口類中搬味,都寫好方法境氢。

  • 在主配置文件中,顯式開啟延遲記載:

    <settings>
      <!-- 默認(rèn)是關(guān)閉碰纬,需要顯式開啟延遲加載 -->
      <setting name="lazyLoadingEnabled" value="true"/>   
      
      <!-- 3.4.1以后萍聊,是默認(rèn)false,可以不寫悦析。開啟后寿桨,調(diào)用任何方法,就會馬上加載屬性强戴。關(guān)閉后亭螟,則是按需加載 -->
      <setting name="aggressivelazyLoading" value="false"/>    
    </settings>
    
  • 在映射配置文件中:

    如:subject調(diào)用findAll時,不會加載user骑歹。只有用到時预烙,才會通過<association ... select="...UserDAOInterface.findOneById">得到對應(yīng)user對象。

    注意:此時<association>中道媚,column屬性不可省略了扁掸。 還有<properties><settings>似乎都有順序要求(<configuraion>中)。放在其他位置會報錯.

      <resultMap type="Subjects" id="UserSubjectsMap">
          <id property="id" column="id" />
          <result property="uid" column="uid"/>
          <result property="name" column="name" />
          <result property="grade" column="grade" />
          <result property="enjoy" column="enjoy" />
          <association property="user" javaType="user" column="uid"                   
              select="com.yinghuo.mybatisCRUD.dao.UserDAOInterface.findOneById"/>
      </resultMap>
    
      <select id="findAll" resultMap="UserSubjectsMap">
          select * from subjects;
      </select>
    
      <select id="findOneById" resultType="Subjects"  parameterType="INT">
          select * from subjects
          <where>
              id=#{id}
          </where>
      </select>
    
    
X對多:

實現(xiàn):與X對一類似最域,區(qū)別:

  • <association>變成<collection>也糊,及其內(nèi)部的屬性:javaType變成ofType
  • column="id",且在從表中羡宙,應(yīng)該要有對應(yīng)的字段狸剃,標(biāo)識該數(shù)據(jù)屬于主表中指定id的。
  • 還有一些就是SQL語句狗热,和兩個實體類結(jié)構(gòu)的小問題了钞馁。

緩存

說明:內(nèi)存用作數(shù)據(jù)庫數(shù)據(jù)的緩存

適用:

  • 經(jīng)常查詢且不經(jīng)常改變的
  • 數(shù)據(jù)正確與否對最終結(jié)果影響不大的

不適用:

  • 經(jīng)常改變的數(shù)據(jù)(不可以使用寫回的策略么?不行匿刮,因為可能存在多個線程或多臺主機(jī)同時操作)
  • 數(shù)據(jù)的正確與否對最終結(jié)果影響很大的僧凰。(如:商品的庫存、銀行的匯率熟丸、股市的牌價)

mybatis中的一級训措、二級緩存

一級緩存:

說明:SqlSession對象里的緩存。(一級緩存是默認(rèn)開啟,不需要手動設(shè)置)

SqlSession在用戶查詢后绩鸣,會緩存結(jié)果怀大,形成一個Map結(jié)構(gòu),當(dāng)再次查詢同一個對象時呀闻,mybatis會先去查看是否SqlSession中是否有對應(yīng)的值化借,如果有則返回,不需要再次訪問數(shù)據(jù)庫捡多。

清空:

SqlSession.clearCache()

或者關(guān)閉sqlSession之后蓖康,再新建:ss=SqlSessionFactory.openSession();

SqlSession自動清空:

時機(jī):當(dāng)調(diào)用SqlSession的commit、update垒手、insert的時候蒜焊,會自動清空緩存。

注意:由于其機(jī)制科贬,可能會導(dǎo)致緩存沒有及時更新泳梆。如果并沒有用該SqlSession進(jìn)行更新、提交等操作唆迁,比如:

  • user = daoProxy.findbyone()鸭丛;
  • 暫停竞穷,并手動修改數(shù)據(jù)庫信息唐责。
  • user2 = daoProxy.findbyone();
  • user == user2 結(jié)果是true瘾带。因為他不會去訪問數(shù)據(jù)庫鼠哥,user2是從緩存中提取的舊結(jié)果,并不是最新的數(shù)據(jù)看政。

二級緩存:

說明:SqlSessionFactory對象里的緩存朴恳。(需要手動設(shè)置開啟)

SqlSessionFactory有一個公共緩存區(qū),可以被其生成的任何SqlSession共享允蚣。只要一個SqlSession進(jìn)行了Commit于颖,就會將如查詢得到的信息緩存在SqlSessionFactory內(nèi)部。

當(dāng)其新建或已建的SqlSession進(jìn)行同樣的查詢時嚷兔,就可以從其內(nèi)部取數(shù)據(jù)森渐,而不需要訪問數(shù)據(jù)庫。

開啟:

默認(rèn)是開啟冒晰,設(shè)置地方:

  • 主配置文件:

    <settings>
      <setting name="cacheEnabled" value="true"/>
    <settings>
    
  • 使用dao映射配置文件.xml:

    <cache/>
    
    <!--然后在方法中聲明使用緩存同衣,下述返回值已使用了別名-->
    <select id="findAll" resultType="User" useCache="true">
          select  * from userx;
    </select>
    
  • 使用注解配置映射:

    ? 注解dao接口,@CacheNamespace(blocking=true)即可壶运。

注意

  • 得到的實體類對象的值是一樣的耐齐,但是不同的對象,如obj1==obj2:false。
  • (*)只有其他SqlSession提交或關(guān)閉之后埠况,才會緩存到SqlSessionFactory中耸携,若沒有提交,則沒有緩存询枚。

mybatis注解開發(fā)

說明:注解與映射文件配置(路徑同于dao接口)违帆,僅可以存在一個。

大致開發(fā)步驟與普通一樣金蜀,僅是主配置文件中刷后,<mapper>配置的是dao接口的地址。

然后在dao接口中渊抄,注釋方法尝胆,并傳入sql語句。即可护桦。

項目:ubuntu--eclipse--mybatisAnnotation

關(guān)于@Results含衔、@ResultMap:

  • 當(dāng)實體類名和數(shù)據(jù)庫名不同時,如果不在sql中用別名二庵,則需要配置映射贪染,如下。

    @Select("select * from user;")
      @Results(id="userMap",value= {
              @Result(id=true,property="uid",column="id"),
              @Result(property="name",column="name"),
              @Result(property="sex",column="sex"),
              @Result(property="address",column="address"),
              @Result(property="city",column="city")
      })
       public List<User> findAll();
    
注解:
  • @Results:兩個屬性:id:唯一標(biāo)識該Results催享; value:包含多個@Result注解杭隙,每個注解對應(yīng)一個字段的映射。
  • @ResultMap:用于其他方法注解因妙,引用一個@Results痰憎。其值標(biāo)準(zhǔn)格式為:value={"id1",”id2”...}攀涵。

多表查詢注解

多對一:

@Results()中铣耘,加入屬性:@Result(property="",column="", one=@One(select="path.to.method", fetchType=FetchType.EAGER))

下面代碼是UserDAOInterfaceUser實體類中包含成員變量Role role以故。

@Select("select u.*,ur.roleId from user as u LEFT JOIN user_role as ur on u.id=ur.userId;")
    @Results(id="userMap",value= {
            @Result(id=true,property="uid",column="id"),
            @Result(property="name",column="name"),
            @Result(property="sex",column="sex"),
            @Result(property="address",column="address"),
            @Result(property="city",column="city"),
            @Result(property="role",column="roleId",javaType=Role.class,
                one=@One(select="com.yinghuo.mybatisAnnotation.                                                   dao.RoleDAOInterface.findOneById", fetchType=FetchType.EAGER)
                    )     
    })
public List<User> findAll();
多對多:

User實體類中包含成員變量List<Role> role蜗细。

說明:在userDAOInterface中與多對一類似,區(qū)別:

  • @Select()中語句變?yōu)椋?code>@Select("SELECT * from user;")

  • one=@One(...)變成many=@Many(...)

  • @One()中怒详,method變成...findByUserId炉媒;其根據(jù)user_role表,和user提供的id棘利,對應(yīng)找到user_role中所有的數(shù)據(jù)項橱野,提取roleId返回role中的多個數(shù)據(jù)項。

  • 以下是RoleDAOInterface.findByUserId:

    @Select("SELECT r.* from role r,user_role ur where ur.userId = #{para} and ur.roleId=r.roleId;")
    List<Role> findByUserId(int userId);
    

緩存

說明:一級緩存是自動開啟的善玫。而二級緩存需要設(shè)置水援。


log4J

properties文檔:(盡量放在resources下)

log4j.rootLogger=debug, stdout, R

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

# Pattern to output the caller's file name and line number.
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n

log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=example.log

log4j.appender.R.MaxFileSize=100KB
# Keep one backup file
log4j.appender.R.MaxBackupIndex=5

log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n

\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014
\u7248\u6743\u58F0\u660E\uFF1A\u672C\u6587\u4E3ACSDN\u535A\u4E3B\u300C\u5C31\u662F\u4E8C\u4E8C\u4E8C\u4E8C\u5A77\u300D\u7684\u539F\u521B\u6587\u7AE0\uFF0C\u9075\u5FAA CC 4.0 BY-SA \u7248\u6743\u534F\u8BAE\uFF0C\u8F6C\u8F7D\u8BF7\u9644\u4E0A\u539F\u6587\u51FA\u5904\u94FE\u63A5\u53CA\u672C\u58F0\u660E\u3002
\u539F\u6587\u94FE\u63A5\uFF1Ahttps://blog.csdn.net/qq_34474324/article/details/98874675

錯誤收集

Result Maps collection does not contain value for ...

  • 說明:在映射配置文件中密强,有一個映射配置文件的select標(biāo)簽中屬性resultType寫成了resultMap
  • 解決方式:檢查所有的配置映射文件(通常上述錯誤描述for后面,會標(biāo)出該錯誤發(fā)生的dao接口蜗元,然后去該接口配置文件看)或渤,看看是不是有寫錯的。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末奕扣,一起剝皮案震驚了整個濱河市薪鹦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌惯豆,老刑警劉巖池磁,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異楷兽,居然都是意外死亡地熄,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門芯杀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來端考,“玉大人,你說我怎么就攤上這事揭厚∪刺兀” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵筛圆,是天一觀的道長裂明。 經(jīng)常有香客問我,道長顽染,這世上最難降的妖魔是什么漾岳? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任轰绵,我火速辦了婚禮粉寞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘左腔。我一直安慰自己唧垦,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布液样。 她就那樣靜靜地躺著振亮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鞭莽。 梳的紋絲不亂的頭發(fā)上坊秸,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天,我揣著相機(jī)與錄音澎怒,去河邊找鬼褒搔。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的星瘾。 我是一名探鬼主播走孽,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼琳状!你這毒婦竟也來了磕瓷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤念逞,失蹤者是張志新(化名)和其女友劉穎困食,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體翎承,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡陷舅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了审洞。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片莱睁。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖芒澜,靈堂內(nèi)的尸體忽然破棺而出仰剿,到底是詐尸還是另有隱情,我是刑警寧澤痴晦,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布南吮,位于F島的核電站,受9級特大地震影響誊酌,放射性物質(zhì)發(fā)生泄漏部凑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一碧浊、第九天 我趴在偏房一處隱蔽的房頂上張望涂邀。 院中可真熱鬧,春花似錦箱锐、人聲如沸比勉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽浩聋。三九已至,卻和暖如春臊恋,著一層夾襖步出監(jiān)牢的瞬間衣洁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工抖仅, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留坊夫,地道東北人毙替。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像践樱,于是被迫代替她去往敵國和親厂画。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,843評論 2 354

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