mybatis在項目中的使用

mybatis在項目中的使用

一、mybatis開發dao層

使用MyBatis開發Dao,通常有兩個方法,即原始Dao開發方法和Mapper動態代理開發方法。

1.1 SqlSession的使用範圍

  • SqlSession中封裝了對數據庫的操作,如:查詢、插入、更新、刪除等。
  • SqlSession通過SqlSessionFactory創建。
  • SqlSessionFactory是通過SqlSessionFactoryBuilder進行創建。

1.1.1 SqlSessionFactoryBuilder

    SqlSessionFactoryBuilder用於創建SqlSessionFacoty,SqlSessionFacoty一旦創建完成就不需要SqlSessionFactoryBuilder了,因爲SqlSession是通過SqlSessionFactory創建的。所以可以將SqlSessionFactoryBuilder當成一個工具類使用,最佳使用範圍是方法範圍即方法體內局部變量。

1.1.2 SqlSessionFactory

    SqlSessionFactory是一個接口,接口中定義了openSession的不同重載方法,SqlSessionFactory的最佳使用範圍是整個應用運行期間,一旦創建後可以重複使用,通常以單例模式管理SqlSessionFactory。

1.1.3 SqlSession

    SqlSession是一個面向用戶的接口,sqlSession中定義了數據庫操作方法。
    每個線程都應該有它自己的SqlSession實例。SqlSession的實例不能共享使用,它也是線程不安全的。因此最佳的範圍是請求或方法範圍。絕對不能將SqlSession實例的引用放在一個類的靜態字段或實例字段中。
       打開一個 SqlSession;使用完畢就要關閉它。通常把這個關閉操作放到 finally 塊中以確保每次都能執行關閉。如下:

SqlSession session = sqlSessionFactory.openSession();
try {
	 // do work
} finally {
	session.close();
}

1.2 原始Dao開發方式

    原始Dao開發方法需要程序員編寫Dao接口和Dao實現類

1.2.1 編寫映射文件

採用mybatis的基礎入門裏面的映射文件mybatis的基礎入門

1.2.2 Dao接口

public interface UserDao {
	//根據id查詢用戶
	User queryUserById(int id);
	//根據用戶名模糊查詢用戶
	List<User> queryUserByUsername(String username);
	//保存用戶
	void saveUser(User user);
}

1.2.3 Dao的實現類

public class UserDaoImpl implements UserDao {
	private SqlSessionFactory sqlSessionFactory;
	public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
		super();
		this.sqlSessionFactory = sqlSessionFactory;
	}
	@Override
	public User queryUserById(int id) {
		// 創建SqlSession
		SqlSession sqlSession = this.sqlSessionFactory.openSession();
		// 執行查詢邏輯
		User user = sqlSession.selectOne("queryUserById", id);
		// 釋放資源
		sqlSession.close();

		return user;
	}
	@Override
	public List<User> queryUserByUsername(String username) {
		// 創建SqlSession
		SqlSession sqlSession = this.sqlSessionFactory.openSession();
		// 執行查詢邏輯
		List<User> list = sqlSession.selectList("queryUserByUsername", username);
		// 釋放資源
		sqlSession.close();
		return list;
	}
	@Override
	public void saveUser(User user) {
		// 創建SqlSession
		SqlSession sqlSession = this.sqlSessionFactory.openSession();
		// 執行保存邏輯
		sqlSession.insert("saveUser", user);
		// 提交事務
		sqlSession.commit();
		// 釋放資源
		sqlSession.close();
	}
}

1.2.4 Dao測試

創建一個JUnit的測試類,對UserDao進行測試,測試代碼如下:

public class UserDaoTest {
	private SqlSessionFactory sqlSessionFactory;
	@Before
	public void init() throws Exception {
		// 創建SqlSessionFactoryBuilder
		SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
		// 加載SqlMapConfig.xml配置文件
		InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
		// 創建SqlsessionFactory
		this.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
	}
	@Test
	public void testQueryUserById() {
		// 創建DAO
		UserDao userDao = new UserDaoImpl(this.sqlSessionFactory);
		// 執行查詢
		User user = userDao.queryUserById(1);
		System.out.println(user);
	}
	@Test
	public void testQueryUserByUsername() {
		// 創建DAO
		UserDao userDao = new UserDaoImpl(this.sqlSessionFactory);
		// 執行查詢
		List<User> list = userDao.queryUserByUsername("張");
		for (User user : list) {
			System.out.println(user);
		}
	}
	@Test
	public void testSaveUser() {
		// 創建DAO
		UserDao userDao = new UserDaoImpl(this.sqlSessionFactory);
		// 創建保存對象
		User user = new User();
		user.setUsername("劉備");
		user.setBirthday(new Date());
		user.setSex("1");
		user.setAddress("蜀國");
		// 執行保存
		userDao.saveUser(user);
		System.out.println(user);
	}
}

1.2.5 問題

原始Dao開發中存在以下問題:
    Dao方法體存在重複代碼:通過SqlSessionFactory創建SqlSession,調用SqlSession的數據庫操作方法
    調用sqlSession的數據庫操作方法需要指定statement的id,這裏存在硬編碼,不得於開發維護

1.3 Mapper動態代理方式(重點)

1.3.1 開發規範

    Mapper接口開發方法只需要程序員編寫Mapper接口(相當於Dao接口),由Mybatis框架根據接口定義創建接口的動態代理對象,代理對象的方法體同上邊Dao接口實現類方法。
    Mapper接口開發需要遵循以下規範:
1、 Mapper.xml文件中的namespace與mapper接口的類路徑相同。
2、 Mapper接口方法名和Mapper.xml中定義的每個statement的id相同
3、 Mapper接口方法的輸入參數類型和mapper.xml中定義的每個sql 的parameterType的類型相同
4、 Mapper接口方法的輸出參數類型和mapper.xml中定義的每個sql的resultType的類型相同

1.3.2 Mapper.xml(映射文件)

定義mapper映射文件UserMapper.xml,將UserMapper.xml放在config下mapper目錄下。
在這裏插入圖片描述

<?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">
<!-- namespace:命名空間,用於隔離sql -->
<!-- 還有一個很重要的作用,使用動態代理開發DAO,1. namespace必須和Mapper接口類路徑一致 -->
<mapper namespace="com.mybatis.mapper.UserMapper">
	<!-- 根據用戶id查詢用戶 -->
	<!-- 2. id必須和Mapper接口方法名一致 -->
	<!-- 3. parameterType必須和接口方法參數類型一致 -->
	<!-- 4. resultType必須和接口方法返回值類型一致 -->
	<select id="queryUserById" parameterType="int"
		resultType="com.mybatis.pojo.User">
		select * from user where id = #{id}
	</select>
	<!-- 根據用戶名查詢用戶 -->
	<select id="queryUserByUsername" parameterType="string"
		resultType="com.mybatis.pojo.User">
		select * from user where username like '%${value}%'
	</select>
	<!-- 保存用戶 -->
	<insert id="saveUser" parameterType="com.mybatis.pojo.User">
		<selectKey keyProperty="id" keyColumn="id" order="AFTER"
			resultType="int">
			select last_insert_id()
		</selectKey>
		insert into user(username,birthday,sex,address) values
		(#{username},#{birthday},#{sex},#{address});
	</insert>
</mapper>

1.3.3 UserMapper(接口文件)

public interface UserMapper {
	//根據id查詢
	User queryUserById(int id);
	//根據用戶名查詢用戶
	List<User> queryUserByUsername(String username);
	//保存用戶
	void saveUser(User user);
}

1.3.4 加載UserMapper.xml文件

修改SqlMapConfig.xml文件,添加以下所示的內容:
在這裏插入圖片描述

1.3.5 測試

public class UserMapperTest {
	private SqlSessionFactory sqlSessionFactory;
	@Before
	public void init() throws Exception {
		// 創建SqlSessionFactoryBuilder
		SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
		// 加載SqlMapConfig.xml配置文件
		InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
		// 創建SqlsessionFactory
		this.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
	}
	@Test
	public void testQueryUserById() {
		// 獲取sqlSession,和spring整合後由spring管理
		SqlSession sqlSession = this.sqlSessionFactory.openSession();
		// 從sqlSession中獲取Mapper接口的代理對象
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		// 執行查詢方法
		User user = userMapper.queryUserById(1);
		System.out.println(user);
		// 和spring整合後由spring管理
		sqlSession.close();
	}
	@Test
	public void testQueryUserByUsername() {
		// 獲取sqlSession,和spring整合後由spring管理
		SqlSession sqlSession = this.sqlSessionFactory.openSession();
		// 從sqlSession中獲取Mapper接口的代理對象
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		// 執行查詢方法
		List<User> list = userMapper.queryUserByUsername("張");
		for (User user : list) {
			System.out.println(user);
		}
		// 和spring整合後由spring管理
		sqlSession.close();
	}
	@Test
	public void testSaveUser() {
		// 獲取sqlSession,和spring整合後由spring管理
		SqlSession sqlSession = this.sqlSessionFactory.openSession();
		// 從sqlSession中獲取Mapper接口的代理對象
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		// 創建保存對象
		User user = new User();
		user.setUsername("劉備");
		user.setBirthday(new Date());
		user.setSex("1");
		user.setAddress("蜀國");
		// 執行查詢方法
		userMapper.saveUser(user);
		System.out.println(user);
		// 和spring整合後由spring管理
		sqlSession.commit();
		sqlSession.close();
	}
}

1.3.6 小結

selectOne和selectList
    動態代理對象調用sqlSession.selectOne()和sqlSession.selectList()是根據mapper接口方法的返回值決定,如果返回list則調用selectList方法,如果返回單個對象則調用selectOne方法。
namespace
    mybatis官方推薦使用mapper代理方法開發mapper接口,程序員不用編寫mapper接口實現類,使用mapper代理方法時,輸入參數可以使用pojo包裝對象或map對象,保證dao的通用性。

二、SqlMapConfig.xml配置文件

2.1 配置內容

SqlMapConfig.xml中配置的內容和順序如下:
  properties(屬性)
  settings(全局配置參數)
  typeAliases(類型別名)
  typeHandlers(類型處理器)
  objectFactory(對象工廠)
  plugins(插件)
  environments(環境集合屬性對象)
    environment(環境子屬性對象)
      transactionManager(事務管理)
      dataSource(數據源)
  mappers(映射器)

2.2 properties(屬性)

SqlMapConfig.xml可以引用java屬性文件中的配置信息如下:
在這裏插入圖片描述SqlMapConfig.xml引用如下:
在這裏插入圖片描述在這裏插入圖片描述注意: MyBatis 將按照下面的順序來加載屬性:
    在 properties 元素體內定義的屬性首先被讀取。
    然後會讀取properties 元素中resource或 url 加載的屬性,它會覆蓋已讀取的同名屬性。

2.3 typeAliases(類型別名)

在這裏插入圖片描述在這裏插入圖片描述

2.4 mappers(映射器)

Mapper配置的幾種方法:

2.4.1 <mapper resource=" " />

使用相對於類路徑的資源(現在的使用方式)
如:<mapper resource=“sqlmap/User.xml” />

2.4.2 <mapper class=" " />

使用mapper接口類路徑
如:<mapper class=“com.mybatis.mapper.UserMapper”/>
注意:此種方法要求mapper接口名稱和mapper映射文件名稱相同,且放在同一個目錄中。

2.4.3 <package name=""/>

註冊指定包下的所有mapper接口
如:<package name=“com.mybatis.mapper”/>
注意:此種方法要求mapper接口名稱和mapper映射文件名稱相同,且放在同一個目錄中。

三、輸入映射和輸出映射

     Mapper.xml映射文件中定義了操作數據庫的sql,每個sql是一個statement,映射文件是mybatis的核心。

3.1 parameterType(輸入類型)

3.1.1 傳遞簡單類型

使用#{}佔位符,或者${}進行sql拼接。

3.1.2 傳遞pojo對象

Mybatis使用ognl表達式解析對象字段的值,#{}或者${}括號中的值爲pojo屬性名稱。

3.1.3 傳遞pojo包裝對象

    開發中通過可以使用pojo傳遞查詢條件。
    查詢條件可能是綜合的查詢條件,不僅包括用戶查詢條件還包括其它的查詢條件(比如查詢用戶信息的時候,將用戶購買商品信息也作爲查詢條件),這時可以使用包裝對象傳遞輸入參數。
    包裝對象:Pojo類中的一個屬性是另外一個pojo。

3.1.3.1 編寫QueryVo

在這裏插入圖片描述

3.1.3.2 Mapper.xml文件

在UserMapper.xml中配置sql,如下圖。
在這裏插入圖片描述

3.1.3.3 Mapper接口

在UserMapper接口中添加方法,如下圖
在這裏插入圖片描述

3.1.3.4 測試方法

在UserMapeprTest增加測試方法,如下:

	@Test
	public void testQueryUserByQueryVo() {
		// mybatis和spring整合,整合之後,交給spring管理
		SqlSession sqlSession = this.sqlSessionFactory.openSession();
		// 創建Mapper接口的動態代理對象,整合之後,交給spring管理
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		// 使用userMapper執行查詢,使用包裝對象
		QueryVo queryVo = new QueryVo();
		// 設置user條件
		User user = new User();
		user.setUsername("張");
		// 設置到包裝對象中
		queryVo.setUser(user);
		// 執行查詢
		List<User> list = userMapper.queryUserByQueryVo(queryVo);
		for (User u : list) {
			System.out.println(u);
		}
		// mybatis和spring整合,整合之後,交給spring管理
		sqlSession.close();
	}

3.1.3.5 效果

在這裏插入圖片描述

3.2 resultType(輸出類型)

3.2.1 輸出簡單類型

3.2.1.1 Mapper.xml文件

在這裏插入圖片描述

3.2.1.2 Mapper接口

在這裏插入圖片描述

3.2.1.3 測試

	@Test
	public void testQueryUserCount() {
		// mybatis和spring整合,整合之後,交給spring管理
		SqlSession sqlSession = this.sqlSessionFactory.openSession();
		// 創建Mapper接口的動態代理對象,整合之後,交給spring管理
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		// 使用userMapper執行查詢用戶數據條數
		int count = userMapper.queryUserCount();
		System.out.println(count);
		// mybatis和spring整合,整合之後,交給spring管理
		sqlSession.close();
	}

3.2.2 輸出pojo對象

參考mybatis的基礎入門

3.2.3 輸出pojo列表

參考mybatis的基礎入門

3.3 resultMap

    resultType可以指定將查詢結果映射爲pojo,但需要pojo的屬性名和sql查詢的列名一致方可映射成功。
    如果sql查詢字段名和pojo的屬性名不一致,可以通過resultMap將字段名和屬性名作一個對應關係 ,resultMap實質上還需要將查詢結果映射到pojo對象中。
    resultMap可以實現將查詢結果映射爲複雜類型的pojo,比如在查詢結果映射對象中包括pojo和list實現一對一查詢和一對多查詢。

3.3.1 聲明pojo對象

public class Order {
	// 訂單id
	private int id;
	// 用戶id
	private Integer userId;
	// 訂單號
	private String number;
	// 訂單創建時間
	private Date createtime;
	// 備註
	private String note;
	get/set方法......
}

3.3.2 Mapper.xml文件

在這裏插入圖片描述

3.3.3 Mapper接口

在這裏插入圖片描述

3.3.4 測試

public class OrderMapperTest {
	private SqlSessionFactory sqlSessionFactory;

	@Before
	public void init() throws Exception {
		InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
		this.sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
	}

	@Test
	public void testQueryAll() {
		// 獲取sqlSession
		SqlSession sqlSession = this.sqlSessionFactory.openSession();
		// 獲取OrderMapper
		OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);

		// 執行查詢
		List<Order> list = orderMapper.queryOrderAll();
		for (Order order : list) {
			System.out.println(order);
		}
	}

}

3.3.5 效果

在這裏插入圖片描述

3.3.6 使用resultMap

     由於上邊的mapper.xml中sql查詢列(user_id)和Order類屬性(userId)不一致,所以查詢結果不能映射到pojo中。
     需要定義resultMap,把orderResultMap將sql查詢列(user_id)和Order類屬性(userId)對應起來
在這裏插入圖片描述

3.3.7 使用resultMap結果展示

在這裏插入圖片描述

四、動態sql

4.1 If標籤

在這裏插入圖片描述

4.2 Where標籤

在這裏插入圖片描述

4.3 Sql片段

Sql中可將重複的sql提取出來,使用時用include引用即可,最終達到sql重用的目的。
在這裏插入圖片描述如果要使用別的Mapper.xml配置的sql片段,可以在refid前面加上對應的Mapper.xml的namespace。
在這裏插入圖片描述

4.4 foreach標籤

向sql傳遞數組或List,mybatis使用foreach解析,如下:根據多個id查詢用戶信息。
在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述

五、關聯查詢

5.1 商品訂單數據模型

在這裏插入圖片描述

5.2 一對一查詢

      需求:查詢所有訂單信息,關聯查詢下單用戶信息。
      注意:因爲一個訂單信息只會是一個人下的訂單,所以從查詢訂單信息出發關聯查詢用戶信息爲一對一查詢。如果從用戶信息出發查詢用戶下的訂單信息則爲一對多查詢,因爲一個用戶可以下多個訂單。
      sql語句:

SELECT
	o.id,
	o.user_id userId,
	o.number,
	o.createtime,
	o.note,
	u.username,
	u.address
FROM
	`order` o
LEFT JOIN `user` u ON o.user_id = u.id

5.2.1 使用resultType

      使用resultType,改造訂單pojo類,此pojo類中包括了訂單信息和用戶信息,這樣返回對象的時候,mybatis自動把用戶信息也注入進來了

5.2.1.1 改造pojo類

在這裏插入圖片描述

5.2.1.2 Mapper.xml

在這裏插入圖片描述

5.2.1.3 Mapper接口

在這裏插入圖片描述

5.2.1.4 測試

在這裏插入圖片描述

5.2.1.5 總結

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

5.2.2 使用resultMap

使用resultMap,定義專門的resultMap用於映射一對一查詢結果

5.2.2.1 改造pojo類

在Order類中加入User屬性,user屬性中用於存儲關聯查詢的用戶信息,因爲訂單關聯查詢用戶是一對一關係,所以這裏使用單個User對象存儲關聯查詢的用戶信息
在這裏插入圖片描述

5.2.2.2 Mapper.xml

	<resultMap type="order" id="orderUserResultMap">
		<id property="id" column="id" />
		<result property="userId" column="user_id" />
		<result property="number" column="number" />
		<result property="createtime" column="createtime" />
		<result property="note" column="note" />
		<!-- association :配置一對一屬性 -->
		<!-- property:order裏面的User屬性名 -->
		<!-- javaType:屬性類型 -->
		<association property="user" javaType="user">
			<!-- id:聲明主鍵,表示user_id是關聯查詢對象的唯一標識-->
			<id property="id" column="user_id" />
			<result property="username" column="username" />
			<result property="address" column="address" />
		</association>
	</resultMap>
	
	<!-- 一對一關聯,查詢訂單,訂單內部包含用戶屬性 -->
	<select id="queryOrderUserResultMap" resultMap="orderUserResultMap">
		SELECT
		o.id,
		o.user_id,
		o.number,
		o.createtime,
		o.note,
		u.username,
		u.address
		FROM
		`order` o
		LEFT JOIN `user` u ON o.user_id = u.id
	</select>

5.2.2.3 Mapper接口

在這裏插入圖片描述

5.2.2.4 測試

在這裏插入圖片描述

5.3 一對多查詢

    案例:查詢所有用戶信息及用戶關聯的訂單信息。用戶信息和訂單信息爲一對多關係。
    sql語句:

SELECT
	u.id,
	u.username,
	u.birthday,
	u.sex,
	u.address,
	o.id oid,
	o.number,
	o.createtime,
	o.note
FROM
	`user` u
LEFT JOIN `order` o ON u.id = o.user_id

5.3.1 改造pojo類

在這裏插入圖片描述

5.3.2 Mapper.xml

	<resultMap type="user" id="userOrderResultMap">
		<id property="id" column="id" />
		<result property="username" column="username" />
		<result property="birthday" column="birthday" />
		<result property="sex" column="sex" />
		<result property="address" column="address" />
	
		<!-- 配置一對多的關係 -->
		<collection property="orders" javaType="list" ofType="order">
			<!-- 配置主鍵,是關聯Order的唯一標識 -->
			<id property="id" column="oid" />
			<result property="number" column="number" />
			<result property="createtime" column="createtime" />
			<result property="note" column="note" />
		</collection>
	</resultMap>
	
	<!-- 一對多關聯,查詢訂單同時查詢該用戶下的訂單 -->
	<select id="queryUserOrder" resultMap="userOrderResultMap">
		SELECT
		u.id,
		u.username,
		u.birthday,
		u.sex,
		u.address,
		o.id oid,
		o.number,
		o.createtime,
		o.note
		FROM
		`user` u
		LEFT JOIN `order` o ON u.id = o.user_id
	</select>

5.3.3 Mapper接口

在這裏插入圖片描述

5.3.4 測試

### 5.3.5 效果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章