mybatis入門案例分析

mybatis入門案例分析

一、設計模式分析
public class MybatisTest {
    public static void main(String[] args) throws Exception{
        //1.讀取配置文件
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.創建SqlSessionFactory工廠
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        //3.使用工廠生產SqlSession對象
        SqlSession session = factory.openSession();
        //4.使用SqlSession創建Dao的代理對象
        IUserDao userDao = session.getMapper(IUserDao.class);
        //5.使用代理對象執行方法
        List<User> users = userDao.findAll();
        for(User user : users) {
            System.out.println(user);
        }
        //6.釋放資源
        session.close();
        in.close();

    }
}
1.讀取配置文件

在讀取文件時,通常有兩種方法,一種是採用絕對路徑,另一種是採用相對路徑。如果採用絕對路徑,其缺點爲不易遷移和部署,在開發時如果我們路徑爲“D:\SqlMapConfig.xml”,部署到服務器時,可能服務器上沒有D盤。相對路徑的缺點就在於,如果項目爲Web工程,部署之後src目錄就不存在了。因此在讀取配置文件時,只有兩種方法:

1.使用類加載器:只能讀取類路徑的配置文件。

2.使用SeverletContext對象的getPath()方法。

2.創建工廠

在創建工廠時,mybatis使用了構建者模式,builder就是構建者,把對象的創建細節隱藏,使用戶直接調用方法便可獲得對象。

3.生產SqlSession對象

生產SqlSession對象時使用了工廠模式,可以降低類間的依賴關係,便於之後對項目進行修改。

4.創建代理對象

創建DAO接口實現類的代理對象實現了使用了代理模式,這樣就不需要自己寫DAO實現類。

二、mybatis執行查詢所有的分析
1.普通的java實現數據庫查詢

1.註冊驅動,獲取connection對象

2.創建數據庫的執行sql的預處理對象

3.執行sql語句

4.封裝查詢結果

5.釋放資源

public class JDBCTest {
    public static void main(String[] args) {
        JDBCTest test=new JDBCTest();
        test.firstJDBC();
    }

    public void firstJDBC(){
        Connection connection=null;
        PrepareStatement prepareStatement=null;
        ResultSet resultSet=null;

        try {
            //1.register,註冊驅動
            DriverManager.registerDriver(new Driver());
            //2.得到數據連接。url格式:jdbc:mysql://主機IP:端口號/數據庫名?user=用戶名&password=密碼
            //因爲MySQL安裝時,端口號默認設置的是3306,所以都是3306
            String url="jdbc:mysql://localhost:3306/sport?user=root&password=12345678";
            connection=DriverManager.getConnection(url);
          
            //3.得到數據庫的執行sql對象
                String sql="select * from player"; //SQL查詢語句
            prepareStatement=connection.prepareStatement();
            //4.執行語句  
            resultSet=prepareStatement.executeQuery();
            while(resultSet.next()){
                //取出查詢的信息
                String name=resultSet.getString("player_name");
                int age=resultSet.getInt("player_age");
                int score=resultSet.getInt("player_score");
                System.out.println("name="+name+",age="+age+",score="+score);
            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally {
            //5.關閉資源
            if(connection!=null){
                try {
                    connection.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if(prepareStatement!=null){
                try {
                    prepareStatement.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if(resultSet!=null){
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

    }


}
2.mybatis中如何實現查詢
<!-- mybatis的主配置文件 -->
<configuration>
    <!-- 配置環境 -->
    <environments default="mysql">
        <!-- 配置mysql的環境 -->
        <environment id="mysql">
            <!-- 配置事務的類型 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置數據源(連接池) -->
            <dataSource type="POOLED">
                <!-- 配置連接數據庫的四個基本信息 -->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="12345678"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 指定映射配置文件的位置,映射配置文件指的是每個dao獨立的配置文件 -->
    <mappers>
        <mapper resource="dao/IUserDao.xml" />
    </mappers>
</configuration>

1.創建connection對象。通過主被配置文件SqlMapConfig.xml,我們可以獲得連接數據庫的信息(驅動、路徑、用戶名和密碼)以及映射配置文件的位置。通過連接數據庫的信息,我們可以構建connection對象。

<mapper namespace="dao.IUserDao">
    <!-- 配置查詢所有 -->
    <select id="findAll" resultType="domain.User">
        select * from user;
    </select>
</mapper>

2.創建prepareStatement對象。通過映射配置文件的信息,我們可以獲得執行的SQL語句和封裝的實體類全限定類名,就可以創建prepareStatement對象。mybatis通過dom4j技術來解析xml文件獲取上述信息。

3.存儲解析結果。在獲取相關信息中後,mybatis需要將執行的SQL語句和封裝結果的實體類全限定類名組合起來定義成一個Mapper對象,每一個Mapper對象對應一個完整String類型的id(namespace+“.”+id)。例如本項目中的SQL語句爲“select * from user;”,封裝結果的實體類全限定類名爲“domain.user”,完整的id爲"dao.IUserDao.findAll",這些都是String類型的字段。

4.利用反射技術封裝。創建prePareStatement對象之後,通過resultSet = prepareStatement.executeQuery();語句我們可以獲得查詢結果集,在對查詢結果集進行封裝時。我們通過完整的id(即封裝結果的全限定類名),利用反射技術(Class.forName("domain.User").getDeclaredConstructor().newInstance();)即可進行封裝。由於實體類的屬性和數據庫表中的列名一致,可以把表的列名當作是實體類的屬性名稱,然後利用反射技術來根據名稱獲取每個屬性,並把值賦進去。反射參考鏈接

三、創建代理對象的分析
//MybatisTest.class
IUserDao userDao = session.getMapper(IUserDao.class);

//DefaultSqlSession.class
public <T> T getMapper(Class<T> type) {
        return this.configuration.getMapper(type, this);
}

//Configuration.class
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return this.mapperRegistry.getMapper(type, sqlSession);
}

//MapperRegistry.class
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
     MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
     if (mapperProxyFactory == null) {
            throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
     } else {
            try {
                return mapperProxyFactory.newInstance(sqlSession);
            } catch (Exception var5) {
                throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
            }
     }
}

//MapperProxyFactory.class
public T newInstance(SqlSession sqlSession) {
        MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
        return this.newInstance(mapperProxy);
}

protected T newInstance(MapperProxy<T> mapperProxy) {
        return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}

//Proxy.class
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
                                          InvocationHandler h) {
        Objects.requireNonNull(h);

        final Class<?> caller = System.getSecurityManager() == null
                                    ? null
                                    : Reflection.getCallerClass();

        /*
         * Look up or generate the designated proxy class and its constructor.
         */
        Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);

        return newProxyInstance(caller, cons, h);
}

上述是MybatisTest類中,getMapper()的調用層級。可以看到最終調用的方法是public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h),這個方法有三個參數,分別是:

1.類加載器loader:使用和被代理對象相同的類加載器

2.代理對象要實現的接口字節碼數組interfaces:和被代理對象實現的是相同的接口

3.代理方式h:就是增強的方法,實際上就是一個InvocationHandler接口的實現類,在實現類中調用selectList方法(查詢所有方法)。

mybatis入門案例,可以參考我的上一篇博客:mybatis入門實例

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