MyBatis的原理及使用和框架概念的引入

MyBatis的學習
1.什麼是框架?
1>什麼是框架?
	框架(Framework)是整個部分或系統的可重用設計,表現爲一組抽象構件及構件實例間交互的方法;另一種定義認爲,框架是可被應用開發者定製者的應用骨架。前者是從應用方面而後者是從目的方面給出的定義
	簡言而之,框架其實就是某種應用的半成品,就是一組組件,供你選用完成你自己的系統,簡單的說就是使用別人搭好的舞臺,你來做表演,而且,框架一般是成熟的不斷升級的軟件
	使用框架的好處:框架封裝了很多的細節,使開發者可以使用極簡的方式實現功能大大提高開發效率
2>三層架構
	表現層:用於展示數據的
	業務層:是處理業務需求的
	持久層:是和數據庫交互的
3>持久層技術解決方案
	JDBC技術:
	Connection,PreparedStatement,ResultSet
	Spring的JdbcTemplate:
	Spring中對jdbc的簡單封裝
	Apache的DBUtils
	它和Spring的JdbcTemplate很像,也是對jdbc的簡單封裝
	以上這些都不是框架JDBC是規範/JdbcTemplate和Apache的DBUtils都只是工具類
	
	JDBC:
public static void main(String[]args){
    Connection connection=null;
    PreparedStatement ps=null;
    ResultSet result=null;
    try{
    Class.forName("com.mysql.jdbc.Driver");
    connection=DriverManger.getCoonection("jdbc;mysql://localhost:3306/Test","root","010313");
    }catch(Exception e){
        .......
    }
}
2.MyBatis框架概述
1>簡述
	(1).mybatis是一個優秀的基於java持久層框架,它內部封裝了jdbc,使開發者只需要關注sql語句本身,而不需要花費精力去處理加載驅動,創建連接,創建statement等繁雜的過程
	(2).mybatis通過xml或註解的方式將要執行的各種statement配置起來,並通過java對象和statement中的sql動態參數進行映射生成最終執行的sql語句,最後由mybatis框架執行sql語句最終由mybatis框架執行sql並將結果映射爲java對象並返回
	(3).採用ORM思想解決了實體和數據庫映射的問題,對jdbc進行了封裝,屏蔽了jdbc api底層訪問細節,使我們不用與jdbc api打交道,就可以完成對數據庫的持久化操作
	(4).mybatis是一個持久層框架,用java編寫的它封裝了jdbc操作的很多細節,使開發者只需要關注sql語句本身而無需關注註冊驅動,創建連接等繁雜過程它使用了ORM思想實現了結果集的封裝
	ORM(Object Relational Mappging)對象關係映射	簡單的說:就是把數據庫表和實體類及實體類的屬性對應起來讓我們操作實體類就實現操作數據庫表
	[實體類中的屬性和數據庫表中的字段名保持一致]
2>Mybatis環境搭建和入門案例
	Mybatis的環境搭建:
		第一步:創建Maven工程並導入座標
		第二步:創建實體類和dao的接口
		第三步:創建Mybatis的主配置文件 SqlMapConfig.xml
		第四步:創建映射配置文件
	環境搭建的主意事項;
		1.創建IUserDao.xml和IUserDao.java時名稱是爲了和我們之前的知識保持一致在MyBatis中它把持久層的操作接口名稱和映射文件也叫做Mapper 所以IUserDao和IUserMapper 是一樣的
		2.在IDEA中創建目錄的時候,它和包是不一樣的包在創建時:com.itxu.dao它是三層的結構 目錄在創建的時候卻是一層目錄 
		3.Mybatis的映射配置文件必須和dao接口的包結構相同
		4.映射配置文件的mapper標籤namespace屬性的取值必須是dao接口的全限定類名
		5.映射配置文件的操作配置,id屬性的取值必須是dao接口的方法名
		當我們遵從了第三四五點,我們在開發中級不需要寫dao的實現類
MyBatis基於代碼模式實現Dao的功能:
	
package com.itxu.test.MybatisTest;
import cn.mybatis.Dao.IUserDao;
import cn.mybatis.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * MyBatis入門案例
 */
public class MyBatisTest {
    public static void main(String[] args) throws IOException {
        //1.讀取配置文件
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
            /**
             *  第一個:使用類加載器,它只能讀取類路徑的配置文件
             *  第二個:使用ServletContext對象的getRealPath();
             * */
        //2.創建SqlSessionFactory工廠
        /**
         *
         * 創建工廠MyBatis使用了/構建者模式
         *  構建者模式:把對象的創建細節隱藏,是使用者直接調用方法即可拿到對象
         *
         * 生產了SqlSession使用了工廠模式
         * 優勢:解耦(降低類之間的依賴關係)
         * */
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(is);
        //3.使用工廠生產SqlSession對象 優勢:解耦(降低類之間的依賴關係)
        SqlSession session = factory.openSession();
        //4.使用SqlSession創建Dao接口的代理對象
        /**
         *
         * 創建Dao接口實現模式實現了代理模式
         *      優勢:不更改源碼的基礎上對已有方法的加強
         * */
        IUserDao userDao = session.getMapper(IUserDao.class);
        //5.使用代理對象執行方法
        List<User> users = userDao.fingetUser();
        for (User user : users)
        {
            System.out.println(user);
        }
        //6.釋放資源
        session.close();
        is.close();
    }
}
	1.讀取配置文件
	2.創建SqlSessionFactory工廠
	3.創建SqlSession
	4.創建Dao接口的代理對象
	5.執行Dao中的方法
	6.釋放資源
		注意:不要忘記在映射配置文件中告知MyBatis要封裝到哪個實體類中
			配置的方式:指定實體類的全限定類名
	
3.使用XML和註解
1>使用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.mybatis.Dao.IUserDao">//指定實體類名的全限定類名
    //<!--配置查詢所有-->
    <select id="fingetUser" resultType="cn.mybatis.domain.User">
        select * from user;
    </select>
</mapper>
 		<mappers>
 		//指定映射配置文件的位置,映射配置文件指的是每個Dao獨立的配置文件
        <mapper resource="com/itxu/Dao/IUserDao.xml"></mapper>
    	</mappers>
2>使用註解來配置
mybatis基於註解的入門案例:
	把IUserDao.xml移除,在Dao接口的方法上使用@Select,並且指定SQL語句同時需要在SqlMapConfig.xml中的mapper的配置中使用class屬性指定Dao接口的全限定類名
	我們在實際開發中都是越簡便越好都是採用不寫Dao實現類的方式不管是用xml還是註解配置 但是mybatis是支持編寫實現類的
	@Select("select * from user")
        <mappers>
                   //如果是用註解的話,此處應該使用class屬性來指定dao的全路徑
        	<mapper class="cn.mybatis.Dao.IUserDao"><mapper>
        </mappers>
4.MyBatis回顧
1>第一步:
SqlSessionFactoryBuilder接收SqlMapConfig.xml文件流,構建出SqlSessionFactory對象
2>第二步:
SqlSessionFactory讀取SqlMapConfig.xml中連接數據庫和mapper映射信息用來生產真正操作數據庫的SqlSession對象
3>第三步:
SqlSession對象有兩大作用:①生成接口代理對象②定義通用增刪改查方法
4>第四步:
作用①:在SqlSessionImpl對象的getMapper方法中分兩步來實現。第一:先用SqlSessionFactory讀取數據庫連接信息創建Connection對象 第二:通過jdk代理模式創建出代理對象作爲getMapper方法返回值,這裏主要工作是在創建代理對象時第三個參數處理類裏面得到sql語句執行對應CURD操作
作用②:在SqlSessionImpl對象中提供selectList()方法[當然實際mybatis框架中海油selectOne,insert等方法]這些方法內也分爲兩步
	第一:用SqlSessionFactory讀取數據庫連接信息創建出jdbc的Connection對象 第二:直接得到Sql語句,使用jdbc的Connection對象進行對應CURD操作
5>第五步:
封裝結果集:無論使用分支一生成代理對象還是直接使用分支二提供的通用CRUD方法我們都要對返回的數據庫結果集進行封裝編程java對象返回給調用者所以我們還必須要知道調用者所需要的返回類型
	總結:通過以上流程不難看出,無論是讓mybatis幫我們創建代理對象還是直接使用mybatis提供的CRUD方法,其本質都是得到jdbc的Connection對象,執行對應得Sql語句,最終封裝結果集。只是註解和xml配置文件兩種開發模式在傳遞sql語句和返回值類型的方式上都有所差異
	註解方式:	@Select("select * from user")
				public List<User>finall();
	xml文件配置的方式:
		<mapper namespace="com.itxu.mapper.UserMapper">
			<select id="finall" resultType="cn.mybatis.domian.User">
				select * from user;
			</select>
		</mapper>			
5.使用MyBatis完成CURD
1>查詢所有操作
	 <!--配置查詢所有-->
    <select id="fingetUser" resultType="cn.mybatis.domain.User">
        select * from user;
    </select>
2>添加信息操作
	<!--保存用戶-->
    <insert id="saveUser" parameterType="cn.mybatis.domain.User">
        insert into user(username,address,sex,birthday)values (#{username},#{address},#{sex},#{birthday});
    </insert>
3>更改信息操作	
	<!--更新用戶-->
    <update id="updateUser" parameterType="cn.mybatis.domain.User">
        update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday}
        where id=#{id};
    </update>
4>刪除信息操作
	 <!--刪除用戶-->
    <delete id="deleteUser" parameterType="java.lang.Integer">
        delete from user where id=#{userid};
    </delete>
5>根據單個信息來查詢數據
  	<!--根據id查詢用戶-->
    <!--同時需要返回結果集需要告訴返回值是什麼類型-->
    <select id="getUserByid" parameterType="java.lang.Integer" resultType="cn.mybatis.domain.User">
        select * from user where id=#{userid};
    </select>
6>模糊查詢的操作
	注意:要在調用該方法的時候添加% %
  <!--使用模糊查詢查詢到用戶的數據-->
    <select id="getUserbyname" parameterType="String" resultType="cn.mybatis.domain.User">
        select * from user where username like #{name};
    </select>
7>使用聚合函數查詢記錄的總數
	  <!--使用聚合函數count查詢user表中的用戶數據-->
    <select id="userCount" resultType="int">
        select count(id)from user;
    </select>
	注意:	        
select * from user where username like '%${value}%';
執行的Sql語句是 select * from user where username like'%王%'(使用的是Statement的拼接S	ql)
select *from user where username like #{name};
執行的Sql語句是 select * from user where username like ?;(使用的是prepateStatement的佔位符)
8>在插入操作之前的到添加數據的編號
	<!--配置插入操作後獲取插入數據的返回值id-->
        <!-- keyProperty:實體類名稱 order:執行順序 resultType:返回類型-->
        <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
            select last_insert_id();
        </selectKey>

9>#{}和${}的區別
	#{}表示一個佔位符號
		通過#{}可以實現preparedStatement向佔位符中設置值,自動進行java類型和jdbc類型轉化#{}可以有效的防止Sql注入,#{}可以接收簡單類型值或pojo屬性值,如果paremeterType傳輸單個簡單類型值,#{}括號中可以是value或是其他值
	${}表示拼接字符串
		通過${}可以將paramererType傳入的內容拼接在Sql中且不進行jdbc類型轉換,${}可以接收簡單類型值或pojo屬性值,如果parameterType傳輸單個簡單類型值,${}括號中只能是value
	注:源碼中指定了讀取的key的名字就是value所以我們就只能叫做value

在實體類名和數據名不同的時候怎麼操作
	1>在配置數據庫文件的時候更改Sql語句(執行效率更快)
		select * from  user where username as userName;
	2>在配置數據庫文件中添加對應關係(執行順序相對慢)
		 <!--配置查詢結果的列名和實體列屬性的對應關係-->
    <resultMap id="userMap" type="cn.mybatis.domain.User">
        <!--主鍵字段的對應-->
        <id property="userid" column="id"></id>
        <!--非主鍵字段的對應-->
        <result property="userName" column="username"></result>
        <result property="userAddress" column="address"></result>
        <result property="userSex" column="sex"></result>
        <result property="userBirthday" column="birthday"></result>
    </resultMap>
 在需要調用的屬性添加resultMap="userMap";
6.OGNL表達式
OBject Graphic Navigation Language(對象圖導航語言)
    通過對象的取值方法來獲取數據,在寫法上把get省略了
    1>獲取用戶的名稱
    	user.getUsername();
    	user.username;
	mybatis中爲什麼能直接寫username而不是user因爲在parameterType中已經提供了屬性所屬的類,所以此時不需要對象名

//用於執行語句判斷、批量操作、映射一對多、多對多關係等等

7.關於配置的加強
1>優化數據庫連接信息的操作使用外部文件
	<!--配置properties
        可以在標籤內部配置數據庫連接的信息,也可以通過屬性引用外部配置文件新
        resource:用於指定配置文件的路徑按照類路徑的寫法來寫並且必須存在類路徑下
        url屬性:要求按照url的寫法來寫地址
        URL:Unifom Resource Locator:統一資源定位符,它是可以唯一標誌一個資源的位置(更精確
        http://localhost:8080/mybatis/demo
        寫法:協議 主機 端口 URI 組成
        URI:Unifom Resource Identifier 統一資源標識符 它是在應用中可以唯一定位一個資源
    -->
    <properties resource="jdbcConfig.properties"></properties>
    //改變DateSource的連接信息
    <dataSource type="POOLED">
                <!--配置連接數據庫的基本信息-->
                <!--jdbc:mysql://localhost:3306/eesy_mybatis-->
                <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>
2>typeAliases標籤和package標籤                                                        
	<!--使用typeAliases配置別名,它只能配置domian中類的別名-->
    	<typeAliases>
			<!--typeAlias用於配置別名type屬性指定的是實體類的全限定類名-->
			<!--alias屬性指定別名,當指定了別名就不在區分大小寫-->
        	typeAlias type="cn.mybatis.domain.User" alias="user"></typeAlias>
<!--用於指定要配置別名的包當指定之後該包下的實體類都會註冊別名,並且類名就是別名不再區分大小寫-->
        <package name="cn.mybatis.domain"></package>
    	</typeAliases>
3>關於Mappers標籤的優化
	  <mappers>
        	<!--<mapper resource="com/itxu/Dao/IUserDao.xml"></mapper>-->
        	<!--是用於指定Dao接口所在的包當指定完成之後就不需要在寫resource,class-->
        	<package name="cn.mybatis.Dao"></package>
    	</mappers>
8.連接池
1>關於連接池的簡介
    連接池:我們在實際開發都會使用連接池,因爲他可以減少我們獲取連接所消耗的時間,就是用於存儲連接的一個容器(容器就是一個集合對象,該集合必須是線程安全的不能是兩個線程拿到同一個連接,同時該線程還必須實現隊列的特性,先進先出)
2>mybatis中的連接池
	連接池提供了三種配置方式:
		主配置文件SqlMapConfig.xml中的dataSource標籤,type屬性就是表示採用何種連接池方式						
	type的取值:
		POOLED:採用傳統javax.sql.DataSource規範中的連接池,mybatis中有針對規範的實現
		UNPOOLED:採用傳統的獲取連接的方式,雖然也實現了Javax.sql.DataSource接口,但是並沒有使用池的思想
		JNDI:採用服務器提供的JDNI實現來獲取DataSource對象不同的服務器所能拿到的DataSource是不一樣的如果不是web或者maven的war工程是不能使用的我們課程中使用的是tomcat服務器 採用的連接池就是dbcp連接池
		
Mybatis中的事務:
	是通過sqlsession對象的commint方法和rollback方法實現事務的提交和回滾
9.動態Sql語句
1>
  動態SQLMyBatis最強大的特性之一一直是它的動態SQL功能。如果您有使用JDBC或任何類似框架的經驗,就會理解有條件地將SQL字符串連接在一起是多麼痛苦,請確保不要忘記空格或忽略列列表末尾的omma。處理動態SQL可能非常困難。雖然使用動態SQL永遠不會有什麼好處,但是MyBatis使用了一種強大的動態SQL語言,可以2>
2>
  在任何映射的SQL語句中使用,這無疑改善了這種情況。
3>
  使用過JSTL或任何類似的基於XML的文本處理器的人都應該熟悉動態SQL元素。在MyBatis的早期版本中,有很多需要了解和理解的元素。MyBatis大大改進了這一點,現在只有不到一半的元素。處理。MyBatis使用強大的基於OGNL的表達式來消除大部分其他元素:
	if
	choose(when,otherwise)
	trim(where,set)
	foreach

4>動態Sql之<if>標籤
	<select id="findByUser" resultType="user" parameterType="user">
			select * from user where1=1
    	<if test="username!=null and username!=''">
    		and username like #{username}
		<if test="address!=null">
			and address like #{username}
	</select>
	注意:<if>標籤的test屬性中寫的是對象的屬性名,如果包裝類的對象要使用OGNL表達式的寫法另外要注意where 1=1的作用(使條件爲真)
5>動態標籤之<where>標籤
	爲了簡便上面 where 1=1的操作我們可以使用where來簡便
	擴展:抽取查詢語句中的重複語句:最終達到Sql可以重用的作用
	<!--抽取重複的Sql語句-->
    <sql id="defaultUser">
          select * from user
    </sql>
	<select id="findByUser" resultType="user" parameterType="user">
			<include refid="defaultUser"></include>
	<where>
    	<if test="username!=null and username!=''">
    		and username like #{username}
		<if test="address!=null">
			and address like #{username}
	<where>
	</select>
	注意:在編寫Sql的時候儘量不要去加分號
/*The error may exist in com/itxu/Dao/IUserDao.xml
### The error may involve cn.mybatis.Dao.IUserDao.findUserInIds-Inline
### The error occurred while setting parameters
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ';*/
6>動態標籤之<foreach>標籤
	當需求發生改變:
		傳入多個 id 查詢用戶信息,用下邊兩個 sql 實現: 
		SELECT * FROM USERS WHERE username LIKE '%張%' AND (id =10 OR id =89 OR id=16) 			SELECT * FROM USERS WHERE username LIKE '%張%' AND id IN (10,89,16) 
		這樣我們在進行範圍查詢時,就要將一個集合中的值,作爲參數動態添加進來。 這樣我們將如何進行參數的傳遞?
	持久層Dao映射配置的編寫:
		<!--查詢所在用戶的id集合-->
<select id="findInids" resultType="user" parametrType="cn.mybatis.domian.QueryVo">
		<!--select * from user where id in(1,2,3,4)-->
            <include refid="defaultUser"></include>
	<where>
		<if text="ids!=null and ids.size()>0"></if>
		<foreach collection="ids" open="id in(" close=")" item="uid" separator=",">
			#{uid}
		</foreach>
	</where>
</select>
		Sql語句:select * from user where id in(?);
	<foreach>標籤用於遍歷集合他們的屬性分別是:
		collection:代表要遍歷的集合元素,注意編寫的時候不要寫${}
		open:代表語句的開始部分
		close:代表語句的結束部分
		item:代表遍歷集合的每個元素生成的變量名
		separator:代表分隔符
		
9.Mybatis中的多表查詢
1>表之間的關係有幾種
	一對多
	多對一
	一對一	
	多對多
舉例:
	用戶和訂單就是(一對多)
		一個用戶可以下多個訂單/多個訂單屬於同一個用戶
	人和身份證就是(一對一)
		一個人只能有一個身份證號/一個身份證號只能有一個人
	學生和老師就是(多對多)
		一個學生可以被多個老師教過/一個老師可以教多個學生
特例:
	如果拿出每一個訂單/他都只能屬於一個用戶所以Mybatis中就把多對一看成了一對一
	mybatis中的多表查詢:
		一個用戶可以有多個賬戶/一個賬戶只能屬於一個用戶(多個賬戶也可以屬於同一個用戶)
	步驟:
	1.建立兩張表:用戶表和賬戶表
讓用戶表和賬戶表之間具備一對多的關係:需要使用外鍵在賬戶表中添加
	2.建立兩個實體類:用戶實體類和賬戶實體類
讓用戶和賬戶的實體類能體現出一對多的關係
	3.建立兩個配置文件
	4.實現配置:
		當我們查詢用戶時可以同時得到用戶下所包含的賬戶信息
		當我們查詢賬戶時,可以同時得到賬戶的所屬用戶信息
實現多對多關係的案例:
	1.建立兩張表:用戶表,角色表
		讓用戶和角色表具有多對多關係,需要使用中間表,中間表中包含各自的主鍵,在中間表是外鍵
	2.建立兩個實體類:用戶實體類和角色實體類
		讓用戶和角色的實體能體現出來多對多的關係
		各自包含對方一個集合引用
	3.建立兩個配置文件
		用戶的配置文件
		角色的配置文件
	4.實現配置
		當我們查詢用戶的時候,可以同時得到用戶所包含的角色信息
		當我們查詢角色的時候,可以同時得到角色的所賦予的用戶信息
2>.一對一關係
	 //從表實體應該包含主表實體的對象引用
	 private User user;
	 並且需要編寫配置文件	
	 <resultMap id="accountUserMap" type="cn.mybatis.domain.Account">
            <id property="id" column="aid"></id>
            <result property="uid" column="uid"></result>
            <result property="money" column="money"></result>
        <!--一對一的關係映射-->
            <association property="user" column="uid" javaType="User">
                <id property="id" column="id"></id>
                <result property="username" column="username"></result>
                <result property="address" column="address"></result>
                <result property="sex" column="sex"></result>
                <result property="birthday" column="birthday"></result>
            </association>
    </resultMap>
	SQL:  select a.*,u.username,u.address from account a,user u where u.id=a.uid;
3>.一對多關係
	//主體表中應該包含從表的集合
	private List<Account> accounts;
	並且需要編寫配置文件
    <!--定義User的ResultMap-->
    <resultMap id="userAccountMap" type="user">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="address" column="address"></result>
        <result property="sex" column="sex"></result>
        <result property="birthday" column="birthday"></result>
        <!--配置User對象中account集合的映射-->
        <collection property="accounts" ofType="Account">
            <id property="id" column="id"></id>
            <result property="uid" column="uid"></result>
            <result property="money" column="money"></result>
        </collection>
    </resultMap>
    Sql: SELECT * from user u LEFT OUTER JOIN account a on u.id=a.uid;
4>多對多關係
	//通過中間表建立關係分別在主表和從表中添加相應的集合
	private List<User>users;
	private List<Role>roles;
	<!--在雙方的配置文件配置對應得ResultMap和collection-->
     IUserDao.xml
       <resultMap id="UserRoleMap" type="user">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="address" column="address"></result>
        <result property="sex" column="sex"></result>
        <result property="birthday" column="birthday"></result>
        <collection property="roles" ofType="role"> //定義集合
            <id property="roleid" column="id"></id>
            <result column="role_name" property="rolename"></result>
            <result column="role_desc" property="roledesc"></result>
        </collection>
    </resultMap>
    IRoleDao.xml<和mapper同>
    <resultMap id="RoleMap" type="role">
        <id property="roleid" column="id"></id>
        <result property="rolename" column="role_name"></result>
        <result property="roledesc" column="role_desc"></result>
        <collection property="users" ofType="user">
            <id property="id" column="id"></id>
            <result property="username" column="username"></result>
            <result property="address" column="address"></result>
            <result property="sex" column="sex"></result>
            <result property="birthday" column="birthday"></result>
        </collection>
    </resultMap>
    Sql: select u.*,r.ROLE_NAME,r.ROLE_DESC from role r LEFT OUTER JOIN user_role ur  on r.ID=ur.RID
       LEFT OUTER JOIN user u on u.id=ur.uid;
	雙左聯雙查詢條件
10.JNDI的知識擴展
JNDI(Java Naming and Directory Interface),java命名和目錄接口和目錄接口是SUN公司提供的一種標準的Java命名系統接口,JNDI提供統一的客戶端API,通過不同的訪問提供者接口JNDI服務供應接口(SPI)的實現,由管理者將JNDI API映射爲特定的命名服務和目錄系統,使得Java應用程序可以和這些命名服務和目錄服務之間進行交互,目錄服務是命名服務的一種自然擴展兩者之間的關鍵差別是目錄服務中對象不但可以有名稱還可以有屬性(例如,用戶有email地址)而命名服務對象卻沒有
	作用:模仿Windows系統的註冊表
	  
<!-- 
<Resource 
name="jdbc/eesy_mybatis"						數據源的名稱
type="javax.sql.DataSource"						數據源類型
auth="Container"								數據源提供者
maxActive="20"									最大活動數
maxWait="10000"									最大等待時間
maxIdle="5"										最大空閒數
username="root"									用戶名
password="1234"									密碼
driverClassName="com.mysql.jdbc.Driver"			驅動類
url="jdbc:mysql://localhost:3306/eesy_mybatis"	連接url字符串
/>

1.在META-INF目錄中建立一個名爲context.xml的配置文件
2.修改SqlMapConfig.xml
	<dataSource type="JNDI">
                <property name="data_source" value="java:comp/env/jdbc/eesy_mybatis"/>
            </dataSource>
11.Mybatis中的延遲加載和立即加載/緩存
1>Mybatis中的延遲加載
	問題:在一對多種,當我們有一個用戶,它有100個賬戶在查詢用戶的時候我們要不要把關聯的賬戶查出來?當查詢賬戶的時候要不要把關聯的用戶查出來
	在查詢用戶時,用戶下的賬戶信息應該是什麼,什麼時候使用,什麼時候查詢的在查詢賬戶時,賬戶的所屬信息應該是隨着賬戶查詢時一起查詢出來
	延遲加載
		在真正使用數據時才發起查詢不用的時候不查詢按需查詢(懶加載)
	立即加載
		不管用戶用不用,只要一調用方法馬上發起查詢
	在對應得四種表關係中:一對多,多對一,一對一,多對多
	關聯的數據是一通常情況下我們都是採用立即加載
	關聯的數據是多通常情況下我們都是採用緩存加載
2>在一對一情況下執行延遲加載
同樣我們也可以在一對多關係配置的<collection>結點中配置延遲加載策略。 <collection>結點中也有 select 屬性,column 屬性
	<settings>
		<!--開啓延遲加載-->
        <setting name="lazyLoadingEnabled" value="true"/>
         <!--按需加載-->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
    //更改Mappeer中的映射配置
    <!--配置User對象中account集合的映射-->
        IAccountMapper.xml
        <association property="user" column="uid" javaType="user" select="cn.mybatis.Dao.IUserDao.getUserByid"></association>
3>在一對多的情況下執行延遲加載
	IUserMapper.xml ()
        <collection property="accounts" ofType="account" select="cn.mybatis.Dao.IAccountDao." column="id"></collection>
        
4>緩存
		1.緩存:存在於內存中的臨時數據
		2.爲什麼使用緩存:減少和數據庫的交互次數,提高執行效率
		3.適用於緩存:經常查詢並且不經常改變的數據的正確與否對最終的結果影響不大的
		4.不適用於緩存的:經常改變的數據數據的正確與否對最終結果影響很大的如:商品的庫存和銀行的匯率
	1).mybatis中的一級緩存
		它指的是Mybatis中SqlSession對象的緩存當我們執行查詢之後查詢的結果會同時存入到SqlSession爲我們提供的一塊區域中該區域的結構是Map集合當我們再次查詢同樣的數據mybatis會先去SqlSession中查詢是否有有的話直接拿出來當SqlSession對象消失時mybatis中的一級緩存也就消失了 
		      session.clearCache(); 用來清除緩存
		一級緩存是 SqlSession 級別的緩存,只要 SqlSession 沒有 flush 或 close,它就存在一級緩存是 SqlSession 範圍的緩存,當調用 SqlSession 的修改,添加,刪除,commit()close()5>二級緩存
	指的是Mybatis中的SqlSessionFactory對象的緩存.由同一個SqlSessionFactory對象創建的SqlSession共享其緩存
	二級緩存的使用使用步驟
		第一步:讓Mybatis框架支持二級緩存(在SqlMapConfig.xml配置)
		第二步:讓當前的映射文件支持二級緩存(在IUserDao.xml中配置)
		第三步:讓當前的操作支持二級緩存(在select標籤中配置)
            二級緩存:存放的內容是數據,而不是對象
12.Java序列化接口的作用
1>Java序列化接口Serializable的作用
	一個對象有對應得一些屬性,把這個對象保存在硬盤上的過程叫做持久化 對象的默認序列化機制寫入的內容是:對象的類,類簽名,以及非瞬態和非靜態字段的值(因爲靜態static的東西在方法區)序列化能把堆內存中的對象的生命週期延長,做持久化操作當下次再需要這個對象的時候我們就不用new 了直接從硬盤中讀取就可以了(存儲到硬盤是一個文件,不需要我們去解析如果用記事本打開解析會出現亂碼,解析要用特定的方式不用我們管我們只需要讀取)把對象存儲到硬盤上的一個文件中這個文件的標準擴展名是(object)
2>什麼樣的數據會進行序列化到硬盤進行持久化
	1)在很多框架中就會有這種object結尾的文件因爲很多對象都不創建,創建起來太麻煩而且對象的值你不知道,框架封存在.object文件中,直接讀取這個文件中的這個值就行了不需要傳這個值
	在搞web開發的時候一些類就需要實現序列化接口因爲服務器就會對你的對象進行臨時的本地存儲它怕服務器崩潰了以後你的會話就會消失所以存儲在了硬盤上你重新啓動服務器恢復之前的會話,恢復對象,你之前運行的東西都在
	2).對某些特定的對象,比如:數據庫連接對象,存儲特定數據的對象,這樣對象你不想創建他們,想存儲起來讓他們的生命週期延長可以把他們放在硬盤當中每次系統啓動的時候都到.object讀取對象裏面的數據,這個時候就可以把他們序列化來完成
	/*Serializable:用於給被序列化的類加入ID號。
用於判斷類和對象是否是同一個版本。 */
 transient:非靜態數據不想被序列化可以使用這個關鍵字修飾。 
3>可能會產生的異常
可能拋出的錯誤 @throws ClassNotFoundException
如果只有obj.object 這個文件能不能把其中的對象Person取出來,因爲任何對象在堆內存中創建都必須依賴於該對象所屬的類文件(class文件),如果僅僅給了obj.object,這個裏面有Person對象的字節碼,可是取出的時候你內存中並沒有Person.class文件,沒有,所以取不出來,所以必須要有obj.object文件和Person.class文件.(所以有一個ClassNotFound異常)
關於程序中的類 ObjectInputStream和ObjectOutputStream 
ObjectInputStream 對以前使用 ObjectOutputStream 寫入的基本數據和對象進行反序列化(意思就是ObjectInputStream只能讀取ObjectOutputStream的)
ObjectOutputStream 和 ObjectInputStream 分別與 FileOutputStream 和 FileInputStream 一起使用時,可以爲應用程序提供對對象的持久存儲。
關於SerializableID
SerializableID號是根據類的特徵和類的簽名算出來的.爲什麼ID號那麼長,是因爲爲了避免重複.所以Serializable是給類加上id用的. 用於判斷類和對象是否是同一個版本。
如果可序列化類未顯式聲明 serialVersionUID,則序列化運行時將基於該類的各個方面計算該類的默認 serialVersionUID 值. 原因是計算默認的 serialVersionUID 對類的詳細信息具有較高的敏感性,根據編譯器實現的不同可能千差萬別,這樣在反序列化過程中可能會導致意外的 InvalidClassException
13.Mybatis基於註解開發的深入解析
>>M共有四種註解方式
	@SELECT @UPDATE @INSERT @DELETE
1>查詢所有
	 @Select("select * from user")
2>添加數據
	 @INSERT("INSERT INTO USER(username,address,sex,birthday) VALUES(#{username},#{address},#{sex},#{birthday})")
3>修改數據
	 @UPDATE("update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where id=#{id}")
4>刪除數據
	 @DELETE("delete from user where id=#{id}")
5>查詢一個用戶
	 @Select("select * from user where id=#{id}")
6>模糊查詢
	  @Select("select * from user where username like #{username}")
    @Select("select * from user where username like '%${value}%'")
7>實體類名與數據庫名不相同的解決方案
	  @Results(id = "userMap",value = {
            @Result(id=true,column = "id",property = "userId"),
            @Result(column = "username",property = "userName"),
            @Result(column = "address",property = "userAddress"),
            @Result(column = "sex",property = "userSex"),
            @Result(column = "birthday",property = "userBirthday"),
    })
      @ResultMap(value={"userMap"})//引用上邊的註解
    
8>Mybatis基於註解開發的一對多或者是多對一的註解配置
			一:	@Result(property = "user",column = "uid",one=@One(select="cn.mybatis.Dao.UserDao.findUserByid",fetchType= FetchType.EAGER)):	@Result(property = "accounts",column = "id",
                    many = @Many(select = "cn.mybatis.Dao.AccountDao.findUserByuid",
                            fetchType = FetchType.LAZY))
9>Mybatis基於註解開發配置二級緩存
	
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章