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)。 |
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 上面挺全的(沒有原始碼解析,原始碼還得回來看我部落格