天天看點

主流架構一:Mybatis架構(4)Mybatis 連接配接池與事務,動态SQL語句以及多表操作一:Mybatis連接配接池與實務深入二:Mybatis 的動态SQL語句三:Mybatis多表查詢之 一對(一)多四:Mybatis多表查詢之 多對多

主流架構一:Mybatis架構(4)Mybatis 連接配接池與事務,動态SQL語句以及多表操作

  • 一:Mybatis連接配接池與實務深入
    • 1.Mybatis連接配接池的分類
    • 2.源碼分析:
    • 3.Mybatis的事務控制:
  • 二:Mybatis 的動态SQL語句
    • (1)if 标簽
    • (2)where 标簽
    • (3)foreach 标簽
      • foreach标簽的屬性:
  • 三:Mybatis多表查詢之 一對(一)多
    • 1. 一對一查詢:
      • 方法一:(定義AccountUser來輸出)
      • 方法二:(resultType為Account來輸出)以後最常用
    • 2. 一對多查詢:(resultMap)
  • 四:Mybatis多表查詢之 多對多
    • 1.實作 Role 到 User 多對多
    • 2.實作 User 到 Role 的多對多

一:Mybatis連接配接池與實務深入

主流架構一:Mybatis架構(4)Mybatis 連接配接池與事務,動态SQL語句以及多表操作一:Mybatis連接配接池與實務深入二:Mybatis 的動态SQL語句三:Mybatis多表查詢之 一對(一)多四:Mybatis多表查詢之 多對多

1.Mybatis連接配接池的分類

連接配接池作為可以減少我們擷取連接配接所消耗的時間的技術。

Mybatis采用的是自己的連接配接池技術,通過主配置檔案SqlMapConfig.xml中的dataSource标簽,type屬性就是表示采用何種連接配接池方式。

<!--            配置資料源(連接配接池)-->
            <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>
           

type屬性的取值:

POOLED 采用傳統的javax.sql.DataSource規範中的連接配接池,mybatis中有針對規範的實作

UNPOOLED 采用傳統的擷取連接配接的方式,雖然也實作Javax.sql.DataSource接口,但是并沒有使用池的思想。

主流架構一:Mybatis架構(4)Mybatis 連接配接池與事務,動态SQL語句以及多表操作一:Mybatis連接配接池與實務深入二:Mybatis 的動态SQL語句三:Mybatis多表查詢之 一對(一)多四:Mybatis多表查詢之 多對多

JNDI 采用伺服器提供的JNDI技術實作,來擷取DataSource對象,不同的伺服器所能拿到DataSource是不一樣。

注意:如果不是web或者maven的war工程,是不能使用的。我們課程中使用的是**tomcat伺服器,采用連接配接池就是dbcp連接配接池。**一般我們采用POOLED的方式,很多時候我們所說的資料源就是為了更好的管理資料庫連接配接,也就是我們所說的連接配接池技術。

2.源碼分析:

(1)Mybatis 中 DataSource 的存取

MyBatis 是通過工廠模式(factory)來建立資料源 DataSource 對象的,MyBatis 建立了 DataSource 執行個體後,會将其放到 Configuration對象内的 Environment 對象中, 供以後使用。

(2)Mybatis 中連接配接的擷取過程分析

建立 SqlSession 對象并需要執行 SQL 語句時,這時候 MyBatis 才會去調用 dataSource 對象來建立java.sql.Connection對象

隻有在要用到的時候,才去擷取并打開連接配接,當我們用完了就再立即将資料庫連接配接歸還到連接配接池中

主流架構一:Mybatis架構(4)Mybatis 連接配接池與事務,動态SQL語句以及多表操作一:Mybatis連接配接池與實務深入二:Mybatis 的動态SQL語句三:Mybatis多表查詢之 一對(一)多四:Mybatis多表查詢之 多對多
主流架構一:Mybatis架構(4)Mybatis 連接配接池與事務,動态SQL語句以及多表操作一:Mybatis連接配接池與實務深入二:Mybatis 的動态SQL語句三:Mybatis多表查詢之 一對(一)多四:Mybatis多表查詢之 多對多

3.Mybatis的事務控制:

JDBC 中事務可以通過手動方式将事務的送出改為手動方式,通過 setAutoCommit()方法就可以開啟事務,然後它是通過sqlsession對象的commit方法和rollback方法實作事務的送出和復原

是以由于Mybatis底層也是使用Connection,是以Mybatis事務送出方法底層也是使用JDBC的setAutoCommit()方法和rollback() commit()

/**
     * 用于在測試方法之後執行
     * @throws Exception
     */
    @After
    public void destory() throws Exception{
        //送出事務
        sqlSession.commit();

        //6.釋放資源
        sqlSession.close();
        in.close();
    }
           

之前的 CUD 操作過程中,我們都要手動進行事務的送出,原因是 setAutoCommit()方法,在執行時它的值被設定為 false 了,是以我們在 CUD 操作中,必須通過 sqlSession.commit()方法來執行送出操作。

CUD 過程中必須使用 sqlSession.commit()送出事務?主要原因就是在連接配接池中取出的連接配接,都會将調connection.setAutoCommit(false)方法,這樣我們就必須使用 sqlSession.commit()方法,相當于使用了 JDBC 中的 connection.commit()方法實作事務送出。明白這一點後,我們現在一起嘗試不進行手動送出,一樣實作 CUD 操作。

使用factory.openSession(true); 此時事務就設定為自動送出了,但是分析知道這種方法隻能送出一份。

主流架構一:Mybatis架構(4)Mybatis 連接配接池與事務,動态SQL語句以及多表操作一:Mybatis連接配接池與實務深入二:Mybatis 的動态SQL語句三:Mybatis多表查詢之 一對(一)多四:Mybatis多表查詢之 多對多
/**
     * 用于在測試方法之前執行
     * @throws Exception
     */
    @Before
    public void init() throws Exception{
        //1.讀取環境裡面的總體配置檔案(裡面參數)
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.建立SqlSessionFactory工廠
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        //3.使用工廠生産一個SqlSession對象(true為送出一個資料時才自動送出事務)
        sqlSession = factory.openSession(true);
        //4.使用SqlSession建立Dao接口的代理對象
        userDao = sqlSession.getMapper(IUserDao.class);
    }
    /**
     * 用于在測試方法之後執行
     * @throws Exception
     */
    @After
    public void destory() throws Exception{
        //送出事務
        //sqlSession.commit();

        //6.釋放資源
        sqlSession.close();
        in.close();
    }
           

雖然這也是一種方式,但就程式設計而言,設定為自動送出方式為 false再根據情況決定是否進行送出,即這種方式更常用。

sqlSession = factory.openSession();
sqlSession.commit();
//6.釋放資源
  sqlSession.close();
  in.close();
           

二:Mybatis 的動态SQL語句

Mybatis 的映射檔案中,前面我們的 SQL 都是比較簡單的,有些時候業務邏輯複雜時,我們的 SQL 是動态變化的,此時在前面的學習中我們的 SQL 就不能滿足要求了。

(1)if 标簽

标簽的 test 屬性中寫的是對象的屬性名(User裡面的),如果是包裝類的對象要使用 OGNL 表達式的寫法。另外要注意 where 1=1 的作用~!

<select id="findUserByCondition" resultMap="userMap" parameterType="user">
    select * from user where 1 = 1
    <if test="userName != null">
        and username = #{userName}
    </if>
    <if test="userSex != null">
        and sex = #{userSex}
    </if>
</select>
           

(2)where 标簽

簡化上面 where 1=1 的條件拼裝,使得SQL語句看起來簡單,我們可以采用标簽來簡化開發。

<select id="findUserByCondition" resultMap="userMap" parameterType="user">
    select * from user
    <where>
    <if test="userName != null">
        and username = #{userName}
    </if>
    <if test="userSex != null">
        and sex = #{userSex}
    </if>
    </where>
</select>
           

(3)foreach 标簽

傳入多個 id 查詢使用者資訊,我們在進行範圍查詢時,就要将一個集合中的值,作為參數動态添加進來。

SQL 語句:

select 字段 from user where id in (?)

foreach 标簽用于周遊集合,它的屬性:

foreach标簽的屬性:

< foreach collection=“ids” open="and id in (" close=")" item = “userId” separator="," >

collection:代表要周遊的集合元素,注意編寫時不要寫#{}

open:代表語句的開始部分

close:代表結束部分

item:代表周遊集合的每個元素,生成的變量名

sperator:代表分隔符,

<!--    根據queryvo中的Id集合實作查詢使用者清單-->
    <select id="findUserInIds" resultMap="userMap" parameterType="queryvo">
        select * from user
        <where>
            <if test="ids != null and ids.size() > 0">
                <foreach collection="ids" open="and id in (" close=")" item = "userId" separator=",">
                    #{userId}
                </foreach>
            </if>
        </where>
    </select>
</mapper>
           

三:Mybatis多表查詢之 一對(一)多

1. 一對一查詢:

方法一:(定義AccountUser來輸出)

(1)定義賬戶資訊的實體類():Account :id,uid(對應使用者的id),money

public class Account implements Serializable {

    private Integer id;
    private Integer uid;
    private Double money;
           

(2)編寫SQL語句:select account.*,user.username, user.address from account, user where account.uid = user.id

(查詢所有的賬号表中的資訊和使用者表中的使用者名和位址,當賬号對應的使用者id與使用者表中user對應)

(3)定義 AccountUser 類:為了能夠封裝上面 SQL 語句的查詢結果(賬号所有資訊和使用者的使用者名和位址),定義 AccountUser 類中要包含賬戶資訊同時還要包含使用者資訊,是以我們要在定義 AccountUser 類時可以繼承 Account 類。

public class AccountUser extends Account {

    private String username;
    private String address;

           

(4)定義層賬戶的持久層Dao接口:

public interface IAccountDao {

    /**
     * 查詢所有商品,同時擷取到目前帳戶的所屬使用者資訊
     * @return
     */
    List<Account> findAll();
    }
           

(5)定義 IAccountDao.xml 檔案中的查詢配置資訊:

<select id="findAllAccout" resultType="accountuser">
        select a.*,u.username,u.address from account a , user u where u.id = a.uid
</select>
           

注意:因為上面查詢的結果中包含了賬戶資訊同時還包含了使用者資訊,是以我們的傳回值類型 returnType

的值設定為 AccountUser 類型,這樣就可以接收賬戶資訊和使用者資訊了。

(6)建立 AccountTest 測試類執行即可。

總結:定義專門的 AccountUser 類作為輸出類型,其中定義了 sql 查詢結果集所有的字段。此方法較為簡單,企業中使用普遍。

方法二:(resultType為Account來輸出)以後最常用

賬戶實體類(Account)中包含使用者

<!--    定義封裝account和user的resultMap-->
    <resultMap id="accountUserMap" type="account">
        <id property="id" column="aid"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>
<!--        一對一的關系映射:配置封裝user的内容-->
        <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>
           

(1)修改賬号實體類(Account):

public class Account implements Serializable {

    private Integer id;
    private Integer uid;
    private Double money;

    //從表實體應該包含一個主表實體的對象引用
    private User user;
           

(2)重新定義 IAccountDao.xml 檔案 (重新寫resultMap)

<!--    定義封裝account和user的resultMap-->
    <resultMap id="accountUserMap" type="account">
        <id property="id" column="aid"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>
<!--    它是用于指定從表方的引用實體屬性的,配置封裝user的内容-->
        <association property="user" 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>
           

2. 一對多查詢:(resultMap)

使用者資訊和他的賬戶資訊為一對多關系(使用者多個賬号的查詢),并且查詢過程中如果使用者沒有賬戶資訊,此時也要将使用者資訊查詢出來,我們想到了左外連接配接查詢比較合适。

(1)編寫 SQL 語句:

select u.*,a.id as aid,a.uid,a.money from account a, user u where u.id = a.id;

(查詢所有使用者表和賬戶的id 使用者id money,從使用者和賬号表,當使用者中id = 賬号的id)

(2)User類加入List< Account> (多個賬号)

public class User implements Serializable {

    private Integer id;
    private String username;
    private String address;
    private String sex;
    private Date Birthday;
    //一對多的關系映射,主表實體應該包含從表實體的集合引用
    private List<Account> accounts;
           

(3) 使用者持久層 Dao 映射檔案配置(IUserDao.xml)

<resultMap type="user" id="userMap">
	<id column="id" property="id"></id>
	<result column="username" property="username"/>
	<result column="address" property="address"/>
	<result column="sex" property="sex"/>
	<result column="birthday" property="birthday"/>
	
	<!-- collection 是用于建立一對多中集合屬性的對應關系ofType 用于指定集合元素的資料類型-->
	<collection property="accounts" ofType="account">
	<id column="aid" property="id"/>
	<result column="uid" property="uid"/>
	<result column="money" property="money"/>
	</collection>
</resultMap>

<!-- 配置查詢所有操作 -->
<select id="findAll" resultMap="userMap">
select account.*,user.username, user.address from account, user where account.uid = user.id
</select>

           

(4)編寫測試方法即可

四:Mybatis多表查詢之 多對多

1.實作 Role 到 User 多對多

使用者與角色的關系模型:

一個使用者可以有多個角色,同理:一個角色可以賦予多個使用者

主流架構一:Mybatis架構(4)Mybatis 連接配接池與事務,動态SQL語句以及多表操作一:Mybatis連接配接池與實務深入二:Mybatis 的動态SQL語句三:Mybatis多表查詢之 一對(一)多四:Mybatis多表查詢之 多對多

(1) 業務要求及實作 SQL:

select u.*,r.id as rid,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
           

(2)編寫角色實體類(Role):

public class Role implements Serializable {

    private Integer roleId;
    private String roleName;
    private String roleDesc;

    //多對多的關系映射:一個角色可以賦予多個使用者
    private List<User> users;
           

(3)編寫 Role 持久層映射配置檔案(IRoleDao.xml):

resultMap為角色,裡面有user

<!--定義role表的ResultMap-->
    <resultMap id="roleMap" type="role">
        <id property="roleId" column="rid"></id>
        <result property="roleName" column="role_name"></result>
        <result property="roleDesc" column="role_desc"></result>
        <collection property="users" ofType="user">
            <id column="id" property="id"></id>
            <result column="username" property="username"></result>
            <result column="address" property="address"></result>
            <result column="sex" property="sex"></result>
            <result column="birthday" property="birthday"></result>
        </collection>
    </resultMap>

    <!--查詢所有-->
    <select id="findAll" resultMap="roleMap">
       select u.*,r.id as rid,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
    </select>
           

(4)最後編寫測試類

2.實作 User 到 Role 的多對多

一個使用者可以具有多個角色,這樣使用者到角色的關系也還是一對多關系。這樣我們就可以認為 User 與 Role 的多對多關系,可以被拆解成兩個一對多關系來實作。

後面的SQL語句,角色實體類, 持久層映射配置檔案同理。

繼續閱讀