mybatis兩種開發方式


本文首先講解從JDBC到mybatis的演變過程,然后是使用mybatis進行開發的兩種方式。

一 JDBC的使用及其優化

1.使用JDBC進行數據庫操作

  • 加載JDBC驅動;

  • 建立並獲取數據庫連接;

  • 創建 JDBC Statements 對象;

  • 設置SQL語句的傳入參數;

  • 執行SQL語句並獲得查詢結果;

  • 對查詢結果進行轉換處理並將處理結果返回;

  • 釋放相關資源(關閉Connection,關閉Statement,關閉ResultSet);

代碼如下:
public static List<Map<String,Object>> queryForList(){  
    Connection connection = null;  
    ResultSet rs = null;  
    PreparedStatement stmt = null;  
    List<Map<String,Object>> resultList = new ArrayList<Map<String,Object>>();  
          
    try {  
        // 加載JDBC驅動  
        Class.forName("com.mysql.jdbc.Driver").newInstance();  
        String url = "jdbc:mysql://localhost:3306/silk";  
              
        String user = "root";   
        String password = "123456";   
              
        // 獲取數據庫連接  
        connection = (Connection) DriverManager.getConnection(url,user,password);   
              
        String sql = "select * from goods where id = ? ";  
        // 創建Statement對象(每一個Statement為一次數據庫執行請求)  
        stmt = (PreparedStatement) connection.prepareStatement(sql);  
              
        // 設置傳入參數  
        stmt.setString(1, "1");  
              
        // 執行SQL語句  
        rs = stmt.executeQuery();  
              
        // 處理查詢結果(將查詢結果轉換成List<Map>格式)  
        ResultSetMetaData rsmd = rs.getMetaData();  
        int num = rsmd.getColumnCount();  
              
        while(rs.next()){  
            Map map = new HashMap();  
            for(int i = 0;i < num;i++){  
                String columnName = rsmd.getColumnName(i+1);  
                map.put(columnName,rs.getString(columnName));  
            }  
            resultList.add(map);  
        }  
              
    } catch (Exception e) {  
        e.printStackTrace();  
    } finally {  
        try {  
            // 關閉結果集  
            if (rs != null) {  
                rs.close();  
                rs = null;  
            }  
            // 關閉執行  
            if (stmt != null) {  
                stmt.close();  
                stmt = null;  
            }  
            if (connection != null) {  
                connection.close();  
                connection = null;  
            }  
        } catch (SQLException e) {  
            e.printStackTrace();  
        }  
    }        
    return resultList;  
}

2.JDBC操作數據庫有哪些問題,如何進行優化呢?

2.1 問題:每一次請求都要進行數據庫的連接和關閉,過於頻繁,浪費資源,降低了系統的性能。

      解決:數據庫的連接和關閉可以通過數據庫連接池來解決,通過連接池可以反復的使用已經建立的連接去訪問數據庫,而不是每次都重新建立一個新的連接。

2.2 問題:連接池有很多種,如c3p0,dbcp,druid 可能存在變化

      解決:可以通過DataSource進行隔離解耦,統一從DataSource獲取數據庫連接,用戶可以通過DataSource來配置使用哪種連接池

2.3 問題:使用JDBC時,sql語句是散落在各個java文件中的,可讀性差不利於維護,改動sql時需要重新打包編譯部署,不利於取出sql在客戶端執行。

      解決:將sql統一放到配置文件中,那么就需要將sql提前加載

2.4 問題:參數傳遞是按順序,根據占位符一一匹配的,那如果是多個不確定的參數,這種方式就顯得很局限了。
       解決:mybatis可以根據參數的不同,生成動態的sql語句
2.5 問題:sql重復 
       解決:將sql統一放到配置文件中,那么只需要修改這一個地方,對所有用到此sql的地方都生效
 
二 mybatis的兩種開發方式
3.原始的dao開發方式:
對於這種開發方式,是直接使用SqlSession提供的方法,通過傳遞statementId和params來操作數據庫,完成與數據庫的交互。但是這種方式不符合面向接口編程的特性,所以就有了后面的Mapper接口代理這種開發方式。
3.1 在spring-ibatis配置文件中配置sqlSessionFactory和sqlSession
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" 
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans  
           http://www.springframework.org/schema/beans/spring-beans.xsd  
           http://www.springframework.org/schema/aop   
           http://www.springframework.org/schema/aop/spring-aop.xsd  
           http://www.springframework.org/schema/tx  
           http://www.springframework.org/schema/tx/spring-tx.xsd  
           http://www.springframework.org/schema/context  
           http://www.springframework.org/schema/context/spring-context.xsd"
	default-autowire="byName">
	
	// 此處配置數據源 省略。。。
<!-- 將數據源映射到sqlSessionFactory中 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="configLocation" value="classpath:mybatis/mybatis-config.xml" /> <property name="dataSource" ref="dataSource" /> </bean> <!-- SqlSession模板類實例 --> <bean id="sessionTemplate" class="org.mybatis.spring.SqlSessionTemplate" destroy-method="close"> <constructor-arg index="0" ref="sqlSessionFactory" /> </bean> </beans>

3.2 編寫dao接口和它的實現類,將sqlSession注入到實現類中  

 BaseDao接口:
public interface BaseDao<T> {

    /**
     * 根據條件獲取一個元素
     * @param paramMap
     * @return
     */
    T get(T entity);
    
    /**
     * 插入記錄
     * @param entity
     */
    int insert(T entity);

    /**
     * 插入記錄(批量)
     * @param list
     * @return
     */
    int insert(List<T> list);
    
    /**
     * 更新記錄
     * @param entity
     * @return
     */
    int update(T entity);

    /**
     * 更新記錄(批量)
     * @param list
     * @return
     */
    int update(List<T> list);
    
    /**
     * 刪除記錄
     * @param obj
     * @return
     */
    int delete(T entity);
   
}

3.3 BaseDaoImpl實現類,並將sqlSession注入到此實現類中,sqlSession中封裝了對數據庫的各種操作:

public abstract class BaseDaoImpl<T> extends SqlSessionDaoSupport implements BaseDao<T> {

    public static final String SQL_SELECT = "select";
    public static final String SQL_SELECT_BY = "selectBy";
    public static final String SQL_SELECT_PAGE = "selectPage";
    public static final String SQL_INSERT = "insert";
    public static final String SQL_DELETE = "delete";
    public static final String SQL_UPDATE = "update";
    public static final String SQL_BATCH_INSERT = "batchInsert";
    
    @Autowired
    protected SqlSessionTemplate sessionTemplate;
    @Autowired
    protected SqlSessionFactory sessionFactory;

@Override @SuppressWarnings("unchecked") public T get(T entity) { if (entity == null) { return null; } Object result = this.getSqlSession().selectOne(this.getSqlName(SQL_SELECT), entity); if (result == null) { return null; } return (T) result; } @Override public int insert(T entity) { if (entity == null) { throw new RuntimeException("T is null"); } int result = this.sessionTemplate.insert(this.getSqlName(SQL_INSERT), entity); return result; } @Override public int insert(List<T> list) { if (list == null || list.size() <= 0) { return 0; } this.sessionTemplate.insert(this.getSqlName(SQL_BATCH_INSERT), list); return list.size(); } @Override public int update(T entity) { if (entity == null) { throw new RuntimeException(""); } int result = this.sessionTemplate.update(this.getSqlName(SQL_UPDATE), entity); return result; }
protected String getSqlName(String sqlId) { StringBuilder sb = new StringBuilder(); sb.append(this.getClass().getName()); sb.append("."); sb.append(sqlId); return sb.toString(); } }

3.4 再編寫對應的Mapper文件,此處省略。

4.Mapper代理開發模式:不需要編寫實現類,只要遵守以下規范,mybatis就可以動態生成Mapper接口的代理類

Mapper代理開發模式需要遵守以下規范:

   4.1 Mapper.xml文件中的namespace與mapper接口的類路徑相同。
   4.2 Mapper接口方法名和Mapper.xml中定義的每個statement的id相同 
   4.3 Mapper接口方法的輸入參數類型和mapper.xml中定義的每個sql 的parameterType的類型相同
   4.4 Mapper接口方法的輸出參數類型和mapper.xml中定義的每個sql的resultType的類型相同

這種開發模式,一般通過sqlSession.getMapper(XXXMapper.class),根據Mapper接口聲明的方法和Mapper映射文件來生成一個Mapper代理對象,當通過這個代理對象調用一個Mapper接口聲明的方法時,會根據方法名和參數來找到Mapper映射文件中

的statementId,底層還是通過sqlSeesion.select(statementId,params)來和數據庫進行交互的。

優缺點比較:Mapper代理開發模式不需要編寫實現類,減少了代碼量,同時是面向接口編程,推薦使用此種方式。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM