1. 程式人生 > >java架構之路-(原始碼)mybatis基本使用

java架構之路-(原始碼)mybatis基本使用

  我們今天先來簡單瞭解一下我們持久層框架,mybatis的使用。而且現在的註解成為趨勢,我主要說一下註解方向的使用吧(配置檔案也會說)

從使用角度只要是三個部分,mybatis-config.xml,mapper.xml,執行檔案三個部分。

mybatis-config.xml:

  主鍵標籤為configuration成對出現的,然後是properties也就是我們的配置,用於配置資料庫。settings宣告一些配置,比如列印sql語句等,後面會一個個去說。然後就是我們的mappers,裡面包含多個mapper標籤,也就是對應我們的mapper.xml檔案,在這裡說一下一共有三種注入的方式,resource,class,url,resource是通過classpath配置的,如果你沒有把mapper放置在resources配置下面,需要在maven裡設定編譯,不然我們的mapper.xml不會編譯到classpath裡,class通過類來注入mapper,url一般是遠端注入的。再就是我們的typehandlers,可以指定型別轉換的。我們也可以繼承BaseTypeHandler來重寫父類的方法來自定義型別轉換。

來一個我自己的簡單配置。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <properties resource="app.properties">
        <property name="jdbc.driver" value="com.mysql.jdbc.Driver"/>
    </properties>

    <settings>
        <!-- 列印查詢語句 -->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <environments default="${default.environment}">
        <environment id="dev">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mybatis/dao/StudentMapper.xml"/>
        <!--        <mapper class="com.tuling.mybatis.dao.UserMapper"></mapper>-->
        <!--        <mapper url="mybatis.dao.StudentDao"></mapper>-->
    </mappers>

</configuration>

配置還要很多,後面原始碼解析裡面會一點點來說明。

mapper.xml:

  這個檔案就是我們的編寫sql的檔案了,裡面主要標籤就是select,insert,update,delete我們的增刪改查標籤,再就是我們的快取設定(二級快取)。下次部落格主要說部落格,原始碼級的。
select裡包含我們常見的id,resultType,resultMap,id用來指向我們的介面檔案的類名,resultType為我們mybatis自帶的型別,也可以是我們設定的物件Bean,resultMap是我們自己定義的返回型別。這裡可能會有疑問,一堆多應該怎麼來配置?
association我們可以用他來指定一對多的配置,同時可以配置懶查詢還是及時查詢的。我們來看一個例項,我們現有學生表格分數表,學生對應很多科目的分數,我們來看一下。先來一段測試程式碼。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost/jdbc"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
<!--        <mapper resource="mybatis/dao/StudentMapper.xml"/>-->
        <mapper class="mybatis.dao.StudentMapper"></mapper>
        <mapper class="mybatis.dao.ScoreMapper"></mapper>
    </mappers>
</configuration>


<?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">
<mapper namespace="mybatis.dao.StudentMapper">
    <select id="selectUser" resultType="mybatis.bean.StudentBean">
        select * from stu where id = #{id}
    </select>
</mapper>
package mybatis.bean;

import java.io.Serializable;

public class StudentBean implements Serializable {

    private static final long serialVersionUID = 2193971369901198487L;
    private int id;
    private String name;
    

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }




    @Override
    public String toString() {
        return "selectUser{" +
                "id=" + id +
                "name=" + name +
                '}';
    }
}
package mybatis;

import mybatis.bean.ScoreBean;
import mybatis.bean.StudentBean;
import mybatis.dao.ScoreMapper;
import mybatis.dao.StudentMapper;
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 org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class Test1 {


    @Test
    public void test() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        SqlSession session = sqlSessionFactory.openSession();
        StudentMapper mapper = session.getMapper(StudentMapper.class);
        StudentBean result = mapper.selectUser(1);

        System.out.println(result);
    }
}

這樣我們查詢到我們的學生資訊,但是還未包含我們的分數。我們來改造一下。

<?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">
<mapper namespace="mybatis.dao.StudentMapper">
    <resultMap id="studentMap" type="mybatis.bean.StudentBean">
        <id property="id" column="id"></id>
        <collection property="scoreBean" ofType="mybatis.bean.ScoreBean">
            <id property="id" column="sid"></id>
<!--            <result property="subject" column="subject"></result>-->
            <result property="score" column="score"></result>
            <result property="studentId" column="studentId"></result>
        </collection>

    </resultMap>

    <select id="selectUser" resultMap="studentMap">
        select t.id,t.name,t.address,t.num,s.id as sid,s.subject,s.score,s.studentId as studentId from student t left join score s on s.studentId = t.id where t.id = #{id}
    </select>
</mapper>

這樣就可以查詢到對應關係了。需要注意的事子表如果和主表重名,一定給子表起一個別名,而且子表的每一項需要寫result,不然沒有結果的,但是還不是很好,本來是一個物件一個集合,現在直接變成集合了,我們再來改改。

<?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">
<mapper namespace="mybatis.dao.StudentMapper">
    <resultMap id="studentMap" type="mybatis.bean.StudentBean">
        <id property="id" column="id"></id>
        <collection property="scoreBean" javaType="java.util.ArrayList" ofType="mybatis.bean.ScoreBean" select="mybatis.dao.ScoreMapper.selectScoreByStudentId" column="{studentId=id}">
        </collection>
    </resultMap>

    <select id="selectUser" resultMap="studentMap">
        select * from student t where t.id = #{id}
    </select>
</mapper>

這個比較好用,但是切記,不是懶載入,不是懶載入,需要注意的是collection的property指定我們實體類Bean類中集合的名字。ofType是指向我們一對多中多方的實體Bean,select指定我們對應的第二句sql語句,也就是我們的子查詢語句。

column="{studentId=id}" 中studentId是我們的子查詢引數名,id是和我們主表的對應關係。就是說,我們要子表的什麼引數等於我們的主表的哪個引數傳遞過去。

 

接下來就是我們簡單的一對一了(也可以當做一對多,但是沒啥卵用的多對一,專案經理讓從多往一查的時候,請你吐他。。。)我們來看我一下我的配置

<?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">
<mapper namespace="mybatis.dao.ScoreMapper">
    <resultMap id="scoreMap" type="mybatis.bean.ScoreBean">
        <id property="id" column="id"></id>
        <result property="subject" column="subject"></result>
        <result property="score" column="score"></result>

        <association property="studentBean" javaType="mybatis.bean.StudentBean" column="studentId">
            <id property="id" column="id"></id>
            <result property="name" column="name"></result>
            <result property="address" column="address"></result>
            <result property="num" column="num"></result>
        </association>
    </resultMap>

    <select id="selectScoreByStudentId" resultMap="scoreMap">
        select * from score s left join student t on s.studentId = t.id where studentId = #{studentId}
    </select>
</mapper>

這個比較簡單,就不說了,就是寫了一個resultMap。我們來看一下兩條sql的怎麼來進行。

<?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">
<mapper namespace="mybatis.dao.ScoreMapper">
    <resultMap id="scoreMap" type="mybatis.bean.ScoreBean">
        <id property="id" column="id"></id>
        <result property="subject" column="subject"></result>
        <result property="score" column="score"></result>

        <association property="studentBean" javaType="mybatis.bean.StudentBean" select="mybatis.dao.StudentMapper.selectUser" column="studentId">
            <id property="id" column="id"></id>
            <result property="name" column="name"></result>
            <result property="address" column="address"></result>
            <result property="num" column="num"></result>
        </association>
    </resultMap>

    <select id="selectScoreByStudentId" resultMap="scoreMap">
        select * from score where studentId = #{studentId}
    </select>
</mapper>

簡單解釋一下,其實和上面collection差不多的,select指定查詢sql位置,column執行傳遞過去的引數。

 

其餘的insert,update,delete都差不多,我這裡就放在一起說了。

id 名稱空間中的唯一識別符號,可被用來代表這條語句。
parameterType 將要傳入語句的引數的完全限定類名或別名。這個屬性是可選的,因為 MyBatis 可以通過型別處理器推斷出具體傳入語句的引數,預設值為未設定(unset)。
parameterMap 這是引用外部 parameterMap 的已經被廢棄的方法。請使用內聯引數對映和 parameterType 屬性。
flushCache 將其設定為 true 後,只要語句被呼叫,都會導致本地快取和二級快取被清空,預設值:true(對於 insert、update 和 delete 語句)。
timeout 這個設定是在丟擲異常之前,驅動程式等待資料庫返回請求結果的秒數。預設值為未設定(unset)(依賴驅動)。
statementType STATEMENT,PREPARED 或 CALLABLE 的一個。這會讓 MyBatis 分別使用 Statement,PreparedStatement 或 CallableStatement,預設值:PREPARED。
useGeneratedKeys (僅對 insert 和 update 有用)這會令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法來取出由資料庫內部生成的主鍵(比如:像 MySQL 和 SQL Server 這樣的關係資料庫管理系統的自動遞增欄位),預設值:false。
keyProperty (僅對 insert 和 update 有用)唯一標記一個屬性,MyBatis 會通過 getGeneratedKeys 的返回值或者通過 insert 語句的 selectKey 子元素設定它的鍵值,預設值:未設定(unset)。如果希望得到多個生成的列,也可以是逗號分隔的屬性名稱列表。
keyColumn (僅對 insert 和 update 有用)通過生成的鍵值設定表中的列名,這個設定僅在某些資料庫(像 PostgreSQL)是必須的,當主鍵列不是表中的第一列的時候需要設定。如果希望使用多個生成的列,也可以設定為逗號分隔的屬性名稱列表。
databaseId 如果配置了資料庫廠商標識(databaseIdProvider),MyBatis 會載入所有的不帶 databaseId 或匹配當前 databaseId 的語句;如果帶或者不帶的語句都有,則不帶的會被忽略。

 useGeneratedKeys=”true”這個相當來說配置的還是比較多的,也就是我們新增成功後,我們的物件可以返回我們插入成功的主鍵ID。

拼裝sql:

  #{}:是預處理,也是一個佔位符的方式來執行sql,${}是sql的拼接,我們其實可以這樣來寫。

   @Select("select * from ${}_sys_log where id=#{condition}")
    public SystemLog findSystemLog(String year,String condition);

也就是說,我們對日誌sys_log表做了分庫分表,按照年份來區分的表,這時我們可以採用sql拼接的方式來做。

但盡力不要用拼接的方式來做,後面我將動態sql會說具體怎麼來實現。${}容易被sql注入。所以我們盡力還用佔位符的方式來處理我們的SQL。

然後就是我們的外掛整合,還有快取,下次部落格我們來說說快取吧。 

 

忘記了,學mybatis的使用,推薦一個網站https://mybatis.org/mybatis-3/zh/index.html  上面挺全的(沒有原始碼解析,原始碼還得回來看我部落格