基礎(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é)果集映射到承載類榨馁。
- 返回代理對象憨栽。
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罩缴。
- 子標(biāo)簽:
-
<dataSource>
:用來配置數(shù)據(jù)源。屬性:POOLED
层扶,表示連接池箫章。- 子標(biāo)簽:多個
<property>
:用來配置連接信息:驅(qū)動、url镜会、用戶名檬寂、密碼。
- 子標(biāo)簽:多個
<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="/../../"
;
- 子標(biāo)簽:
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))
下面代碼是UserDAOInterface
,User
實體類中包含成員變量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接口蜗元,然后去該接口配置文件看)或渤,看看是不是有寫錯的。