天天看點

Mybatis架構學習第四節:MyBatis實作基本SQL操作

此部落格用于個人學習,來源于ssm架構的書籍,對知識點進行一個整理。

四、基于代理 Dao 實作 CRUD 操作:

要求:

  1. 持久層接口和持久層接口的映射配置必須在相同的包下。
  2. 持久層映射配置中 mapper 标簽的 namespace 屬性取值必須是持久層接口的全限定類名。
  3. SQL 語句的配置标簽,,,的 id 屬性必須和持久層接口的

    方法名相同。

4.1 根據 ID 查詢:

4.1.1 在持久層接口中添加 findById 方法:
/**
* 根據 id 查詢
* @param userId
* @return
*/
User findById(Integer userId);
           
4.1.2 在使用者的映射配置檔案中配置:
<!-- 根據 id 查詢 --> 
<select id="findById" resultType="com.itheima.domain.User" parameterType="int">
	select * from user where id = #{uid}
</select>
           

注意點:

sql 語句中使用#{}字元:它代表占位符,相當于原來 jdbc 部分所學的?,都是用于執行語句時替換實際的資料,具體的資料是由#{}裡面的内容決定的。

#{}中内容的寫法:由于資料類型是基本類型,是以此處可以随意寫。

4.1.3 在測試類添加測試:
public class MybastisCRUDTest {
	private InputStream in ;
	private SqlSessionFactory factory;
	private SqlSession session;
	private IUserDao userDao;
	
	@Test
	public void testFindOne() {
		//6.執行操作
		User user = userDao.findById(41);
		System.out.println(user);
	}
	
	@Before//在測試方法執行之前執行
	public void init()throws Exception {
		//1.讀取配置檔案
		in = Resources.getResourceAsStream("SqlMapConfig.xml");
		//2.建立建構者對象
		SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
		//3.建立 SqlSession 工廠對象
		factory = builder.build(in);
		//4.建立 SqlSession 對象
		session = factory.openSession();
		//5.建立 Dao 的代理對象
		userDao = session.getMapper(IUserDao.class);
	}

	@After//在測試方法執行完成之後執行
	public void destroy() throws Exception{
		session.commit();
		//7.釋放資源
		session.close();
		in.close();
	} 
}
           

4.2 儲存操作:

4.2.1 在持久層接口中添加新增方法:
/**
* 儲存使用者
* @param user
* @return 影響資料庫記錄的行數
*/
int saveUser(User user);
           
4.2.2 在使用者的映射配置檔案中配置:
<!-- 儲存使用者--> 
<insert id="saveUser" parameterType="com.itheima.domain.User">
	insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>
           

注意,這上面用了ognl 表達式——是 apache 提供的一種表達式語言,全稱是:Object Graphic Navigation Language 對象圖導航語言,它是按照一定的文法格式來擷取資料的。

文法格式就是使用 #{對象.對象}的方式,#{user.username} 它會先去找 user 對象,然後在 user 對象中找到 username 屬性,并調用 getUsername() 方法把值取出來。但是我們在 parameterType 屬性上指定了實體類名稱,是以可以省略 user.,而直接寫 username。

4.2.3 添加測試類中的測試方法:
@Test
public void testSave(){
	User user = new User();
	user.setUsername("modify User property");
	user.setAddress("北京市順義區");
	user.setSex("男");
	user.setBirthday(new Date());
	System.out.println("儲存操作之前:"+user);
	//5.執行儲存方法
	userDao.saveUser(user);
	System.out.println("儲存操作之後:"+user);
}
           

需要注意的是,此時應該修改結束後的代碼,加上一句:

再釋放資源,這樣才能保證資料庫中的資料有更新。

4.2.4 擷取新增使用者 id 的傳回值:

新增使用者後,同時還要傳回目前新增使用者的 id 值,因為 id 是由資料庫的自動增長來實作的,是以就相

當于我們要在新增後将自動增長 auto_increment 的值傳回。

<insert id="saveUser" parameterType="USER">
<!-- 配置儲存時擷取插入的 id --> 
	<selectKey keyColumn="id" keyProperty="id" resultType="int">
		select last_insert_id();
	</selectKey>
	insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>
           

4.3 使用者更新:

4.3.1 在持久層接口中添加更新方法:
/**
* 更新使用者
* @param user
* @return 影響資料庫記錄的行數
*/
int updateUser(User user);
           
4.3.2 在使用者的映射配置檔案中配置:
<!-- 更新使用者 --> 
<update id="updateUser" parameterType="com.itheima.domain.User">
	update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
</update>
           
4.3.3 加入更新的測試方法:
@Test
public void testUpdateUser()throws Exception{
	//1.根據 id 查詢
	User user = userDao.findById(52);
	//2.更新操作
	user.setAddress("北京市順義區");
	int res = userDao.updateUser(user);
	System.out.println(res);
}
           

4.4 使用者删除:

4.4.1 在持久層接口中添加删除方法:
/**
* 根據 id 删除使用者
* @param userId
* @return
*/
int deleteUser(Integer userId);
           

4.4.2 在使用者的映射配置檔案中配置:

<!-- 删除使用者 --> 
<delete id="deleteUser" parameterType="java.lang.Integer">
	delete from user where id = #{uid}
</delete>
           
4.4.3 加入删除的測試方法:
@Test
public void testDeleteUser() throws Exception {
	//6.執行操作
	int res = userDao.deleteUser(52);
	System.out.println(res);
}
           

4.5 使用者模糊查詢:

4.5.1 在持久層接口中添加模糊查詢方法:
/**
* 根據名稱模糊查詢
* @param username
* @return
*/
List<User> findByName(String username);
           
4.5.2 在使用者的映射配置檔案中配置:
<!-- 根據名稱模糊查詢 --> 
<select id="findByName" resultType="com.itheima.domain.User" parameterType="String">
 	select * from user where username like #{username}
</select>
           
4.5.3 加入模糊查詢的測試方法:
@Test
 public void testFindByName(){
	 //5.執行查詢一個方法
	 List<User> users = userDao.findByName("%王%");
	 for(User user : users){
		 System.out.println(user);
	 }
 }
           

注意:我們在配置檔案中沒有加入%來作為模糊查詢的條件,是以在傳入字元串實參時,就需要給定模糊查詢的辨別%。配置檔案中的#{username}也隻是一個占位符,是以 SQL 語句顯示為“?”。

4.5.4 模糊查詢的另一種配置方式:

第一步:修改 SQL 語句的配置,配置如下:

<!-- 根據名稱模糊查詢 --> 
<select id="findByName" parameterType="string" resultType="com.itheima.domain.User">
 	select * from user where username like '%${value}%'
</select>
           

我們在上面将原來的#{}占位符,改成了${value}。注意如果用模糊查詢的這種寫法,那麼${value}的寫法就是固定的,不能寫成其它名字。

第二步:測試,如下:

/**
* 測試模糊查詢操作
 */
@Test
public void testFindByName(){
	 //5.執行查詢一個方法
	List<User> users = userDao.findByName("王");
	for(User user : users){
		System.out.println(user);
	} 
}
           
4.5.5 #{}與${}的差別:

#{}表示一個占位符号:通過#{}可以實作 preparedStatement 向占位符中設定值,自動進行 java 類型和 jdbc 類型轉換,#{}可以有效防止 sql 注入。 #{}可以接收簡單類型值或 pojo 屬性值。 如果 parameterType 傳輸單個簡單類型值,#{}括号中可以是 value 或其它名稱。

${}表示拼接 sql 串:通過${}可以将 parameterType 傳入的内容拼接在 sql 中且不進行 jdbc 類型轉換,${}可以接收簡單類型值或 pojo 屬性值,如果 parameterType 傳輸單個簡單類型值,${}括号中隻能是 value。

4.6 查詢使用聚合函數:

4.6.1 在持久層接口中添加模糊查詢方法:
/**
* 查詢總記錄條數
* @return
*/
int findTotal();
           
4.6.2 在使用者的映射配置檔案中配置:
<!-- 查詢總記錄條數 --> 
<select id="findTotal" resultType="int">
	select count(*) from user;
</select>
           
4.6.3 加入聚合查詢的測試方法:
@Test
public void testFindTotal() throws Exception {
	//6.執行操作
	int res = userDao.findTotal();
	System.out.println(res);
}
           

4.7 Mybatis 與 JDBC 程式設計的比較

  1. 資料庫連結建立、釋放頻繁造成系統資源浪費進而影響系統性能,如果使用資料庫連結池可解決此問題。

    解決:在 SqlMapConfig.xml 中配置資料連結池,使用連接配接池管理資料庫連結。

  2. Sql 語句寫在代碼中造成代碼不易維護,實際應用 sql 變化的可能較大,sql 變動需要改變 java 代碼。

    解決:将 Sql 語句配置在 XXXXmapper.xml 檔案中與 java 代碼分離。

  3. 向 sql 語句傳參數麻煩,因為 sql 語句的 where 條件不一定,可能多也可能少,占位符需要和參數對應。

    解決:Mybatis 自動将 java 對象映射至 sql 語句,通過 statement 中的 parameterType 定義輸入參數的類型。

  4. 對結果集解析麻煩,sql 變化導緻解析代碼變化,且解析前需要周遊,如果能将資料庫記錄封裝成 pojo 對象解析比較友善。

    解決:Mybatis 自動将 sql 執行結果映射至 java 對象,通過 statement 中的 resultType 定義輸出結果的類型。