連接池
- 連接池可以減少獲取連接所消耗的時間和性能,就像一個容器,把連接初始化後放在這個容器裏,當要用的時候就取出連接,可以說連接池就是一個用於存儲連接的容器,該容器使用集合實現,該集合必須是線程安全的,不能兩個線程拿到統一的連接,該集合還必須有隊列的特性(先進先出)
- Mybatis連接池提供了 3 種方式的配置
(1)配置的位置:主配置文件的dataSource
標籤,其type屬性就是表示採用何種連接池,其值有三種:
❤POOLED 採用傳統的java.sql.DataSource規範中的連接,Mybatis中有針對規範的實現,每次使用的時候就從池中獲取一個來用
❤UNPOOLED 採用傳統的獲取連接的方式,雖然也實現了java.sql.DataSource接口,但是並沒有使用池的思想,每次使用的時候就創建一個新的連接來用
❤JNDI 採用服務器提供的JNDI技術實現來獲取DATaSource對象,不同的服務器所能拿到的DataSource是不同的,如果不是web或者maven的var工程是不能使用的
。
(2)POOLED工作流程:首先查看空閒區,如果空閒區還有連接就直接拿來用,如果空閒區中的連接已經沒有了,那麼會去查看活動區,看看活動區中的活動連接數量是否已經到達了最大數量,如果已經到達了最大數量,就判斷這裏面那個是最先進來的,也就是最老的,將其返回。
實際開發中使用的是Tomcat服務器,採用的連接池就是dbcp連接池
(3)JNDI:Java Naming and Directory Interface
(Java命名和目錄接口),是SUN公司提供的一種標準的Java命名系統接口,目的是模仿windows
系統中的註冊表,在服務器中註冊數據源。
❤windows 註冊表可以堪稱是一個Map<key,calue>
這樣的結構,value在JNDI中存儲的就是對象,key存的就是路徑+名稱。
❤在Tomcat服務器啓動時會準備一個這樣的數據源結構,這樣在web的項目中能使用到。
❤在web 項目中需要在JSP中才能使用,在test測試類中反而是用不了,因爲test類中沒有Tomcat服務器提供的數據源,因此無法使用,而在JSP中就可以使用。
事務控制以及設計方法
事務的基本概念
- 一項事務是由一條或多條操作數據庫的SQL語句組成的一個不可分割的工作單元,即事務可理解爲邏輯上的一組操作,組成這組操作的各個單元,要麼都成功,要麼有一個失敗就全部失敗,例如銀行轉賬
- 事務的4個特性(原子性,一致性,隔離性,持久性)
- 不考慮隔離產生的3個問題
髒讀即一個事務讀取到另一個事務未提交的數據;
不可重複讀即一個事務讀到了另一個事務已經提交的update數據,導致同一個事務中的多次查詢結果不一致;
虛讀即一個事物讀到了另一個事務已經提交的insert的數據,導致同一個事務中的多次查詢結果不一致; - 事務的4種隔離級別(MySQL中默認的隔離級別 - repeatable read)
Mybatis中的事務操作
- Mybatis 中是通過 SqlSession 對象的
commit()
和rollback()
實現事務的提交和回滾 - 但是在實際開發中,除非每次對數據庫的操作只有一個纔會設置自動提交,否則都不會使用這種方式
// 3 使用工廠生產SqlSession對象
// 使用true參數可設置自動提交
sqlSession = factory.openSession(true);
// 5.2 提交事務,如果不提交會自動回滾
//設置了自動提交過後可不必再用代碼手動提交
sqlSession.commit();
Mybatis 基於XML配置的動態SQL語句的使用
- 使用了
if where foreach sql
標籤的SQL語句後面的;
號可以不加,由Mybatis自行判斷條件決定是否結束語句 - if 標籤:根據不同的情況拼接不同的查詢條件
(1)在sql語句的地方,大小寫無關緊要,但是涉及到實體類的,要在實體類中查找值的就要注意大小寫問題,所以實體類和數據庫表最好使用統一的名稱
(2)where後面的1=1是爲了能夠讓if標籤裏面的語句能連上,避免產生錯誤
(3)當需要多個條件組合判斷時,不能用&&,要用and
符號連接<!-- 根據條件查詢 --> <select id="selectByCondition" resultType="user" parameterType="user"> select * from user where 1=1 <if test="userName!=NULL"> and userName = #{userName} </if> </select>
- where 標籤
(1)如果語句太多,頻發使用where 1=1
來連接會沒那麼美觀,於是有了where標籤,Mybatis會根據where中的條件判斷是否需要加上條件<!-- where標籤的使用 --> <select id="selectByCondition" resultType="user" parameterType="user"> select * from user <where> <if test="userName!=NULL"> and userName = #{userName} </if> </where> </select>
- foreach 標籤:類似於sql語句中的子查詢
(1)在QueryVo對象中添加屬性,在接口類中添加方法,配置映射
(2)collection 代表要便利的集合元素
(3)open 代表語句開始部分 close 代表語句結束部分
(4)item 代表遍歷集合的每個元素,生成的變量名,跟後面#{}
中括號裏面的變量名要一致
(5)separator 代表分隔符<!-- 根據QueryVo對象中的id集合實現查詢用戶列表 --> <select id="selectByCondition" resultType="user" parameterType="user"> select * from user <where> <if test="ids!=NULL and ids.size>0"> <foreach collection="ids" open="and id in (" close=")" item="id" separator=","> #{id} </foreach> </if> </where> </select>
- sql 標籤:抽取重複的SQL語句
<sql id="defaultSql"> select * from user </sql> <select id="" resultType=""> <include refid="defaultSql"></include> </select>
多表查詢
實現流程:
(1)建立兩張表,用戶表和賬戶表
(2)建立兩個實體類,用戶類和賬戶類
(3)通過外鍵讓兩張表具備一對多的關係,也要讓兩個實體類能體現出一對多的關係
(4)建立兩個配置文件
(5)實現配置:當查詢用戶時,能夠同時得到用戶下包含的賬戶信息或查詢賬戶時能夠得到賬戶所屬的用戶信息
一對多
- 一對多和多對一可以分開分析
例如一個用戶可以下多個訂單,而多個訂單屬於同一用戶
對於用戶是一對多,對於訂單是多對一 - 但是拿出每一個訂單,都只能屬於一個用戶,所以 Mybatis 中把多對一看成了一對一
- Mybatis 會自動識別出查詢結果重複的地方並封裝好
- 當查詢結果中出現重複的列名時,要在SQL語句中將重複了的列名改成唯一的別名
- 實現步驟 查詢用戶下的所有賬號
(1)在從表中添加對方作爲屬性private List<Account> accounts;
(2)新建一個接口類的方法List<Account> findAll();
(3)在配置文件中配置映射關係
(4)調用查詢
<!-- 返回所有用戶並獲取其賬戶 -->
<!-- 定義User的resultMap -->
<resultMap id="userAccountMap" type="user">
<id property="id" column="id"/>
<result property="userName" column="userName"/>
<result property="age" column="age"/>
<!-- 配置user對象中accounts對象集合的映射 -->
<collection property="accounts" ofType="com.learn.domain.Account">
<id property="id" column="aid"/>
<id property="id" column="money"/>
</collection>
</resultMap>
<select id="findAllUserAndAccount" resultMap="userAccountMap">
select * from user u left outer join account a on u.id = a.id
</select>
//調用執行
public void testFindAll() {
//獲取所有用戶
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println("-----每個用戶的信息-----");
//打印當前用戶
System.out.println(user);
//打印當前用戶的所有賬號
System.out.println(user.getAccounts());
}
}
一對一
- 實現步驟
(1)在從表中添加對方作爲屬性private User user;
(2)新建一個接口類的方法List<Account> findAll();
(3)在配置文件中配置映射關係
(4)調用查詢
<!-- 定義封裝account和user的resultMao -->
<resultMap id="accountUserMap" type="account">
《
<id property="id" column="aid"/>
<result property="uid" column="uid"/>
<result property="money" column="money"/>
<!-- 一對一的關係映射,配置封裝user的內容 -->
<!-- 相當於配置account中剛添加的user對象 -->
<association property="user" column="uid">
<id property="id" column="id"/>
<result property="userName" column="userName"/>
<result property="age" column="age"/>
</association>
</resultMap>
<!-- 查找全部賬號並顯示其用戶的信息 -->
<select id="findAll" resultMap="accountUserMap">
select a.id as aid, a.uid, a.money, u.* from user u, account a where u.id = a.uid
</select>
//調用執行
public void testFindAll() {
List<Account> accountList = accountDao.findAll();
for (Account account : accountList) {
System.out.println("-------------------------");
System.out.println(account);
System.out.println(account.getUser());
}
}
(5)輸出結果
多對多
- 例如:一個用戶有多個角色,一個角色有多個用戶
- 實現步驟
(1)建立兩張表,並讓兩張表具有多對多的關係:需要有中間表,並且有兩張表的主鍵
(2)建立兩個實體類,並讓這兩個實體能體現出多對多的關係:兩個實體類都各種包含對方的對象集合引用
(3)建立兩個配置文件
(4)實現配置,調用方法。實現當查詢用戶時能查詢到該用戶的所有角色,當查詢角色時能夠查詢該角色下的所有用戶 - 注意:當sql語句很長需要換行的時候,或前或後最好加上一個空格,以免再執行的時候將頭尾的詞語連接在一起,沒有空格作爲分隔符,防止出錯。
兩個實體類
public class User{
private List<Role> roles;
}
public class Role{
private List<User> users;
}
配置文件
<!-- Role的配置文件 IRoleDao.xml -->
<resultMap id="roleMap" type="role">
<id property="roleId" column="rid"/>
<result property="roleName" column="role_name"/>
<result property="roleDesc" column="role_desc"/>
<collection property="users" ofType="user">
<id property="id" column="id"/>
<result property="userName" column="userName"/>
<result property="age" column="age"/>
</collection>
</resultMap>
<select id="fildAll" resultMap="roleMap">
select u.*,r.id as rid,r.rolename,r.role_desc from role r
left outer join on r.id=ur.rid
left outer join user u on u.id=ur.uid
</select>
<!-- Role的配置文件 IUserDao.xml -->
<resultMap id="userMap" type="user">
<id property="id" column="id"/>
<result property="userName" column="userName"/>
<result property="age" column="age"/>
<collection property="roles" ofType="role">
<id property="roleId" column="rid"/>
<result property="roleName" column="role_name"/>
<result property="roleDesc" column="role_desc"/>
</collection>
</resultMap>
<select id="fildAll" resultMap="roleMap">
select u.*,r.id as rid,r.rolename,r.role_desc from user u
left outer join on u.id=ur.uid
left outer join user u on r.id=ur.rid
</select>