Mybatis學習筆記(二) 之Dao開發

来源:http://www.cnblogs.com/airsen/archive/2017/01/11/6273016.html
-Advertisement-
Play Games

使用Mybatis開發Dao,通常有兩個方法,即原始Dao開發方法和Mapper介面開發方法,常用還是Mapper介面開發。 SqlSession的使用範圍 SqlSession中封裝了對資料庫的操作,如:查詢、插入、更新、刪除等。通過SqlSessionFactory創建SqlSession,而S ...


使用Mybatis開發Dao,通常有兩個方法,即原始Dao開發方法和Mapper介面開發方法,常用還是Mapper介面開發。

SqlSession的使用範圍

public class test1 {
    private static SqlSessionFactory sqlSessionFactory;
    private static Reader reader; 
    //創建會話工廠,傳入mybatis的配置文件信息
    static{
        try{
        	//得到配置文件流
            reader = Resources.getResourceAsReader("Configuration.xml");
            //創建會話工廠,傳入mybatis的配置文件信息
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);                   
        }catch(Exception e){
            e.printStackTrace();
        }
    }         
    //查詢數據
    public void select() {
    	//通過工廠得到sqlsession
        SqlSession session = sqlSessionFactory.openSession();
        try {
        	//通過SqlSession操作資料庫//第一個參數:映射文件中statement的id//第二個參數:指定和映射文件所匹配的parameterType類型參數
	        User user = (User) session.selectOne("com.yihaomen.mybatis.model.User.selectUserByID", 1);
        } finally {
        	session.close();
        }
    }
}

想要通過mabatis對資料庫操作,除了要各種配置之外,最終在測試的時候,需要創建特定對象,上圖示例:

1、SqlSessionFactoryBuilder

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

2、SqlSessionFactory

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

3、SqlSession

SqlSession是一個面向用戶的介面, sqlSession中定義了資料庫操作,預設使用DefaultSqlSession實現類。

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

結論:

每個線程都應該有它自己的SqlSession實例。SqlSession的實例不能共用使用,它也是線程不安全的。因此最佳的範圍是請求或方法範圍。絕對不能將SqlSession實例的引用放在一個類的靜態欄位或實例欄位中。

打開一個 SqlSession;使用完畢就要關閉它。通常把這個關閉操作放到 finally 塊中以確保每次都能執行關閉。

    	//通過工廠得到sqlsession
        SqlSession session = sqlSessionFactory.openSession();
        try {
        } finally {
          session.close();
        }

 原始Dao開發方式

程式員需要編寫DAO和DAO的實現類。需要向DAO實現類中註入SqlSessionFactory,在方法體內通過SqlSessionFactory來創建SqlSession。

1、定義Dao介面

public interface UserDAO{

    //根據本id查詢用戶
    User findUserById(int id) throws Exception;    
    //添加用戶
    void insertUser(User user) throws Exception;   
    //根據id刪除用戶
    void deleteUser(int id) throws Exception;
}

2、Dao實現類

DAO實現類
/**
* @ClassName: UserDAOImpl 
* @Description: DAO實現類(註意:SqlSession是非線程安全的,故不能聲明為全局的)
 */
public class UserDAOImpl implements UserDAO {

    SqlSessionFactory sqlSessionFactory;
    /**
     * 向DAO實現類中註入SqlSessionFactory(此處通過構造方法註入)
     */
    public UserDAOImpl(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
    }
    
    @Override
    public User findUserById(int id) throws Exception {
        
        SqlSession sqlSession = sqlSessionFactory.openSession();
        User user = sqlSession.selectOne("test.findUserById", id);
        sqlSession.close();
        return user;
    }

    @Override
    public void insertUser(User user) throws Exception {
        
        SqlSession sqlSession = sqlSessionFactory.openSession();
        sqlSession.insert("test.insertUser", user);
        sqlSession.commit();
        sqlSession.close();
    }

    @Override
    public void deleteUser(int id) throws Exception {
        
        SqlSession sqlSession = sqlSessionFactory.openSession();
        sqlSession.delete("test.deleteUser", id);
        sqlSession.commit();
        sqlSession.close();
    }

}

3、新建一個源代碼目錄命名為test,在UserDAOImpl類中滑鼠右鍵新建一個Junit Test Case,更換源代碼目錄為test並勾選我們需要測試的方法:

public class UserDAOImplTest {

    private SqlSessionFactory sqlSessionFactory;
    
    /**
     * 此方法在執行測試之前執行,得到一個SqlSessionFactory
     */
    @Before
    public void setUp() throws Exception {
        
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("SqlMapConfig.xml"));
    }

    @Test
    public void testFindUserById() throws Exception {
        // 創建UserDAO(在構造中註入SqlSessionFactory)
        UserDAO userDAO = new UserDAOImpl(sqlSessionFactory);
        User user = userDAO.findUserById(1);
        System.out.println(user);
    }

    @Test
    public void testInsertUser() throws Exception {
        UserDAO userDAO = new UserDAOImpl(sqlSessionFactory);
        User user = new User();
        user.setSex("2");
        user.setUsername("孫悟空");
        user.setAddress("方寸靈臺山");
        user.setBirthday(new Date());
        userDAO.insertUser(user);
    }

    @Test
    public void testDeleteUser() throws Exception {
        UserDAO userDAO = new UserDAOImpl(sqlSessionFactory);
        userDAO.deleteUser(27);
    }

}

原始DAO開發中存在的問題

  • DAO的介面實現類中存在大量的模板方法,設想:可以將重覆的代碼提取出來。

  • 在SqlSession的方法時將Statement的id硬編碼在你DAO的實現類中。

  • 調用sqlSession的相關方法傳入參數是泛型,即使傳入錯誤的參數,在編譯階段也不會報錯,不利於程式員開發。

Mapper動態代理方式

實現原理

Mapper介面開發方法只需要程式員編寫Mapper介面(相當於Dao介面),由Mybatis框架根據介面定義創建介面的動態代理對象,代理對象的方法體同上邊Dao介面實現類方法。

Mapper介面開發需要遵循以下規範:Mapper可以自動生成Mapper介面實現類代理對象。

1、 Mapper.xml文件中的namespacemapper介面的類路徑相同。

2、  Mapper介面方法名和Mapper.xml中定義的每個statementid相同

3、 Mapper介面方法的輸入參數類型和mapper.xml中定義的每個sql parameterType的類型相同

4、 Mapper介面方法的輸出參數類型和mapper.xml中定義的每個sqlresultType的類型相同

1、UserMapper.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">

<!-- namespace命名空間,作用就是對sql進行分類化管理,註意:使用mapper代理方法開發,namespace有特殊重要作用 -->
<mapper namespace="com.yihaomen.mybatis.dao.IUserOperation">
	<!-- 在映射文件中配置很多sql -->
	<!-- id標識映射文件的sql,稱為statement的id ,將sql語句封裝到mappedStatement對象中,所以將id稱為statement的id
	parameterType:指定輸入類型  resultType:指定sql輸出結果的所映射的java對象,select指定resultType表示將單挑記錄
	映射成java對象-->
    <select id="selectUserByID" parameterType="int" resultType="User">
        select * from `user` where id = #{id}
    </select>
    
    <insert id="addUser" parameterType="User" 
        useGeneratedKeys="true" keyProperty="id"> 
        insert into user(userName,userAge,userAddress) values(#{userName},#{userAge},#{userAddress})  
    </insert>  
    
    <update id="updateUser" parameterType="User">
        update user set userName=#{userName},userAge=#{userAge},userAddress=#{userAddress} where id=#{id}
    </update>
    
    <delete id="deleteUser" parameterType="int">
        delete from user where id=#{id}
    </delete>
    
    <select id="list"  resultType="User">
        select * from `user`
    </select>
    
    <!-- ${}表示拼接sql串,指定就是單挑記錄所映射的java對象類型,使用${}拼接,容易導致sql註入
    ${value}:拼接輸入參數的內容,如果傳入類型是簡單類型,${}中只能使用value -->
    <select id="findUserByName"  parameterType="String"  resultType="User">
        select * from `user` where username like '%${value}%'        
    </select>
</mapper>

2、UserMapper.java類

package com.yihaomen.mybatis.dao;

import java.util.List;

import com.yihaomen.mybatis.model.Article;
import com.yihaomen.mybatis.model.User;

//註意:介面名字必須與  xml中的namespace名字一樣   2、介面實現方法每個名字  與xml中的id對應
public interface IUserOperation {   
	//查詢數據
    public User selectUserByID(int id);    
    //增加數據
    public void addUser(User user);   
    //更新數據
    public void updateUser(User user);    
    //刪除數據
    public void deleteUser(int id);
    //聯合查詢
    public List<Article> getUserArticles(int id);    
    //list獲取
    public List<User> list();    
    //模糊查詢
    public List<User> findUserByName(String name);
    
}

完成前面2步之後不要忘了在映射文件SqlMapConfig.xml中載入UserMapper.xml哦!

<!-- 配置映射文件 -->
<mappers>
    <mapper resource="sqlmap/User.xml"/>
    <mapper resource="mapper/UserMapper.xml"/>
</mappers>

3、針對UserMapper介面測試

package com.yihaomen.mybatis.ui;

import java.io.Reader;
import java.util.List;

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 com.yihaomen.mybatis.dao.IUserOperation;
import com.yihaomen.mybatis.model.User;

public class Test {
    private static SqlSessionFactory sqlSessionFactory;
    private static Reader reader; 

    //創建會話工廠,傳入mybatis的配置文件信息
    static{
        try{
        	//得到配置文件流
            reader = Resources.getResourceAsReader("Configuration.xml");
            //創建會話工廠,傳入mybatis的配置文件信息
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
                    
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    //公共方法,返回初始化的sqlSessionFactory對象
    public static SqlSessionFactory getSession(){
        return sqlSessionFactory;
    }
    
    //查詢數據
    public void select() {
    	//通過工廠得到sqlsession
        SqlSession session = sqlSessionFactory.openSession();
        try {
        	//通過SqlSession操作資料庫
        	//第一個參數:映射文件中statement的id
        	//第二個參數:指定和映射文件所匹配的parameterType類型參數
	        User user = (User) session.selectOne("com.yihaomen.mybatis.model.User.selectUserByID", 1);
	        System.out.println(user.getUserAddress());
	        System.out.println(user.getUserName());
        } finally {
        	session.close();
        }
    }
    
    //增加數據
    public void addUser(String address,String name){
    	//創建user對象
        User user=new User();
        user.setUserAddress(address);
        user.setUserName(name);
        user.setUserAge(80);
        
        //通過工廠得到SqlSession
        SqlSession session = sqlSessionFactory.openSession();
        try {
            IUserOperation userOperation=session.getMapper(IUserOperation.class);
            //添加數據
            userOperation.addUser(user);
            //提交
            session.commit();
            //System.out.println("當前增加的用戶 id為:"+user.getId());
        } finally {
            session.close();
        }
    }
    
    //更新數據
    public void updateUser(int id,String address){
        //先得到用戶,然後修改,提交。
        SqlSession session = sqlSessionFactory.openSession();
        try {
            IUserOperation userOperation = session.getMapper(IUserOperation.class);
            User user = userOperation.selectUserByID(id);            
            user.setUserAddress(address);
            userOperation.updateUser(user);
            session.commit();
            System.out.println("更新成功!!");
        } finally {
            session.close();
        }
    }
    
    //刪除數據
    public void deleteUser(int id) {
    	SqlSession session = sqlSessionFactory.openSession();
    	
    	try{
    		IUserOperation userOperation = session.getMapper(IUserOperation.class);
            userOperation.deleteUser(id);
            session.commit();  
            System.out.println("刪除數據:id= "+id);
    	}finally {
            session.close();
        }
		
	}
    
    //list獲取
    public void getList() {
    	SqlSession session = sqlSessionFactory.openSession();
    	
    	try{
    		IUserOperation userOperation = session.getMapper(IUserOperation.class);
    		List<User> us = userOperation.list();    		
    		session.commit();  
            //System.out.println("生成list: "+us.size());
    	}finally {
            session.close();
        }
		
	}
    
    //模糊查詢
    public void geFindUserByName(String name) {
    	SqlSession session = sqlSessionFactory.openSession();
    	
    	try{
    		IUserOperation userOperation = session.getMapper(IUserOperation.class);
    		List<User> us = userOperation.findUserByName(name);   
    		System.out.println(us.size());
    		session.commit();  
    		
    	}finally {
            session.close();
        }
		
	}


	public static void main(String[] args) {
		Test test = new Test();
		//test.getList();		
		test.geFindUserByName("小");
		//test.addUser("杭州","小江");


	    }

        
}
  • 我們比較疑問的就是我們在UserMapper.xml的根據用戶名查找用戶的ResultType使用的是普通的POJO,但是我們自己的Mapper介面中返回值是List類型。這不就造成了類型不一致麽?但是,實際上代理對象內部調用了selectOne()或者selectList(),代理對象內部會自動進行判斷是否是單獨的POJO選用合適的方法。

  • Mapper介面中方法的參數只有一個是否會影響系統的維護?DAO層的代碼是被業務層公用的,即使Mapper介面的參數只有一個我們也可以使用包裝的POJO來滿足系統需求。

  • 註意:持久層中方法的參數中可以使用包裝類型,但是Service層中不建議使用包裝類型(不利於業務層的拓展維護)。

 

  

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 恢復內容開始 http://ironpython.net/documentation/dotnet/這是原文地址 以下筆記僅記錄閱讀過程中我認為有必要記錄的內容,大多數都是依賴翻譯軟體的機翻,配合個人對代碼的理解寫出的筆記,個別不是很確定的,會在句首標註 猜測: 在ironPython 中想使用.N ...
  • 沒時間扯淡類,趕緊上車吧。 在現代社會中,信息安全對於每一個人都是至關重要的,例如我們的銀行賬戶安全、支付寶和微信賬戶安全、以及郵箱等等,說到信息安全,那就必須得提到加密技術,至於加密的一些相關概念,在這裡就不說了。 這一次將會主要講解.NET的加密方式,接下來將會分別介紹散列加密,對稱加密,非對稱 ...
  • 成員的可訪問性 如果沒有顯示聲明成員的可訪問性,編譯器通常預設選擇private。CRL要求介面類型的所有成員都具有public可訪問性。 一個派生類重寫在他的基類型中定義的一個成員時,c#編譯器要求原始成員和重寫成員具有相同的可訪問性。(CRL不需要) 任何成員想要被別人訪問到,都必須在一個可見的 ...
  • 背水一戰 Windows 10 之 控制項(佈局類): Panel, Canvas, RelativePanel, StackPanel, Grid ...
  • 舉個例子: 帶輸入參數的存儲過程計算班級中英語和數學不及格的人數 if(exists(select * from sys.objects where name='usp_GetFailCount')) drop proc usp_GetFailCount go create proc usp_Get ...
  • 前臺用過jquery ajax將值傳遞到 後臺的一般處理程式 並且報了這個異常 原因是:前臺傳遞過來的時間格式不對 需要把 "/"換成 "-" 例如:2017-01-10 ...
  • 分析器錯誤 說明: 在分析向此請求提供服務所需資源時出錯。請檢查下列特定分析錯誤詳細信息並適當地修改 分析器錯誤消息: 未能創建類型“StockManageWebService.Service1”。源錯誤: 行 1: <%@ Page Language="C#" AutoEventWireup="t ...
  • 大家都知道,現在和以前比起來,互聯網行業、軟體行業已經天差地別了。現在處處都在搞信息化建設,人人都知道互聯網思維。這樣的信息化時代,對於軟體開發者、對於軟體開發公司來說,是一個巨大的機遇。 在門外漢看來,軟體開發是機遇大、成本低,只要叫幾個程式員,就能搞出個軟體公司來。但是,事實情況是這個樣子嗎?本 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...