首發日期:2018-10-31python
與JDBC的對比中,MyBatis是基於ORM的,自然要比JDBC強,基於ORM使得MyBatis具備查詢的數據能夠自動封裝到對象中的等好處,而JDBC須要手動編碼的位置就較多了(就算是使用DButils,你也須要使用定義不一樣的方法來給不一樣的持久類賦值。)。mysql
在互聯網應用程序開發中,對於存儲過程和複雜的SQL,Hibernate並無很好地去處理,因此它比較難提高性能(並非說不能,而是耗費心思較多),沒法知足高併發和高響應的需求(若是要強行優化,又破壞了Hibernate的全自動ORM設計)。git
與之對應的,Mybatis能夠說是基於SQL的,它須要咱們去自定義SQL,那麼咱們能夠根據須要去設計和優化SQL,這種可針對SQL的優化的持久層框架,恰巧符合高併發和高響應的互聯網應用程序開發開發需求。github
1.首先要下載依賴包https://github.com/mybatis/mybatis-3/releasessql
2.建立普通javase工程,導入依賴包(我這裏使用mybatis-3.4.5 ):數據庫
3.建立持久類和建立數據表:持久類是用於封裝從數據庫中返回的結果,能夠說持久類的對象就是數據庫記錄在java中的實體(這裏約定數據表的列名與持久類的屬性名一致)。apache
package work.pojo; public class User { private Integer id; private String name; private Integer age; //省略setter,getter,toString }
create table user( id int primary key auto_increment, name varchar(20), age int );
4.在持久類User.java同級目錄下建立映射文件user.xml:這個映射文件的意義是用來定義sql語句,使得咱們能夠在代碼中調用sql語句【不一樣類的標籤訂義不一樣類的SQL,id用於標識SQL語句,parameterType是傳入SQL語句的參數,resultType定義了返回結果的類型(這裏因爲表字段和類屬性名一致,查詢的記錄的各個值會自動賦給對象)】設計模式
<?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="user"> <!--id用於標識SQL,parameterType是傳給SQL的參數的類型,resultType是返回結果的類型 --> <select id="getUserById" parameterType="int" resultType="work.pojo.User" > <!-- 使用#{}來傳入參數 --> SELECT * FROM USER WHERE id = #{id} </select> </mapper>
5.配置mybatis配置文件,這裏命名爲mybatis-config.xml
。配置文件的意義是配置MyBatis的運行設置,MyBatis是針對持久層的框架,因此它必需要有數據庫鏈接的配置。數組
<?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用來定義數據庫鏈接環境,environments用來定義多個environment --> <environment id="development"> <!-- transactionManager配置事務管理,使用jdbc事務管理 --> <transactionManager type="JDBC" /> <!-- dataSource配置數據庫鏈接池 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mybatis" /> <property name="username" value="root" /> <property name="password" value="123456" /> </dataSource> </environment> </environments> <mappers> <!-- 導入映射文件,這樣MyBatis才能管理到SQL語句 --> <mapper resource="work/pojo/user.xml"/> </mappers> </configuration>
6.編寫測試方法:
配置文件配完後,要想經過mybatis操做數據庫,那麼就須要使用SqlSessionFactoryBuilder、SqlSessionFactory和SqlSession幾個對象。
@Test public void test1() throws IOException { // 建立SqlSessionFactoryBuilder對象 SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder(); // 經過Mybatis包的Resources類來將配置文件轉成輸入流 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); // 加載配置文件輸入流,建立SqlSessionFactory對象 SqlSessionFactory sqlSessionFactory = sfb.build(inputStream); // sqlSessionFactory建立SqlSession對象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 執行查詢,第一個參數是映射文件中定義的SQL的id名,第二個參數是傳給SQL的參數。 User user = sqlSession.selectOne("getUserById", 1); // 輸出查詢結果 System.out.println(user); // 釋放資源 sqlSession.close(); }
這裏給一下文件結構、數據表數據和測試結果。
文件結構:
數據表數據:
測試結果:User [id=1, name=沙僧, age=18]
上面演示了MyBatis的使用,相信你對MyBatis已經有了一個初步的瞭解,下面將對各個部分的知識進行講解。
1.核心組件【關於SqlSessionFactoryBuilder這些對象,以及瞭解Mybatis的運行流程】
2.mybatis配置文件的配置【關於數據庫鏈接之類的配置】
3.映射文件的配置【關於SQL語句的定義方式】
以傳入一個配置文件的字節輸入流對象爲例,MyBatis提供了一個Resource類,它能夠很方便地將配置文件轉成輸入流:
// 建立SqlSessionFactoryBuilder對象 SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder(); // 經過Resources類來將配置文件轉成輸入流,Resources是mybatis提供的 InputStream inputStream=Resources.getResourceAsStream("mybatis-config.xml"); // 加載配置文件輸入流,建立SqlSessionFactory對象 SqlSessionFactory sqlSessionFactory = sfb.build(inputStream);
sqlSession.commit();
。// sqlSessionFactory建立SqlSession對象 SqlSession sqlSession = sqlSessionFactory.openSession(); //開啓自動提交,默認增、刪、改是不自動提交的 //SqlSession sqlSession = sqlSessionFactory.openSession(true);
SqlSession的做用相似於JDBC中的Connection對象。
使用示例:
SqlSession sqlSession = sqlSessionFactory.openSession(); User user = new User(); user.setName("鐵頭娃"); user.setAge(4); //發送sql sqlSession.insert("insertUser", user); //提交事務 sqlSession.commit(); // 釋放資源 sqlSession.close();
若是這個接口遵循了Mapper的開發規範,而且有對應的映射文件,那麼sqlSession調用getMapper方法能夠獲取一個mapper對象,mapper對象能夠直接調用接口方法來執行映射文件中對應的SQL語句。
sqlSession.getMapper(某個接口.class);
功能:
Mapper也能夠發送SQL,調用Mapper接口中的方法就至關於sqlSession調用映射文件中的SQL。【這樣的調用是徹底面向對象的,如今廣泛用這種。】
SqlSession sqlSession = sqlSessionFactory.openSession(); //發送sql UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.getUserById(1); //User user = sqlSession.selectOne("getUserById", 1); //原方式 System.out.println(user); // 釋放資源 sqlSession.close();
稍微瞭解了一下核心組件以後,再回頭看一下以前的代碼:
@Test public void test1() throws IOException { // 建立SqlSessionFactoryBuilder對象 SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder(); // 經過Mybatis包的Resources類來將配置文件轉成輸入流 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); // 加載配置文件輸入流,建立SqlSessionFactory對象 SqlSessionFactory sqlSessionFactory = sfb.build(inputStream); // sqlSessionFactory建立SqlSession對象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 執行查詢,第一個參數是映射文件中定義的SQL的id名,第二個參數是傳給SQL的參數。 User user = sqlSession.selectOne("getUserById", 1); // 輸出查詢結果 System.out.println(user); // 釋放資源 sqlSession.close(); }
咱們如今先來了解一些映射文件的配置,也就是映射文件裏面所謂的SQL語句之類的怎麼寫。這裏瞭解了映射文件怎麼配置以後,你能夠先使用sqlSession來執行SQL體驗一下其中的意義的。
SqlSession sqlSession = sqlSessionFactory.openSession(); User user = new User(); user.setName("鐵頭娃"); user.setAge(4); //發送sql sqlSession.insert("insertUser", user); //提交事務 sqlSession.commit(); // 釋放資源 sqlSession.close();
映射文件須要dtd約束,在依賴包沒有包含dtd的配置方法,只能從官方文檔中獲取,這裏給一下。
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
基礎結構,下面是一個大體的映射文件結構,在mapper標籤下面配置其餘標籤:
<?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="user"> <select id="getUserById" parameterType="int" resultType="work.pojo.User" > SELECT * FROM USER WHERE id = #{id} </select> </mapper>
命名空間.SQL ID
。select標籤用來定義查詢類的SQL語句。
命名空間.SQL ID
來調用對應的SQL語句。】示例:
<select id="getUserById" parameterType="int" resultType="user" > SELECT * FROM USER WHERE id = #{id1} </select>
#{參數名}
來向SQL語句傳遞參數。
<select id="getUserById" parameterType="int" resultType="work.pojo.User" > SELECT * FROM USER WHERE id = #{id1} </select>
對於對象類型,因爲對象中有屬性,因此要使用#{屬性名}
來把對象中的數據傳遞給SQL。若是對象的屬性仍是一個對象那麼可使用#{內含對象名.屬性名}
。
<!-- 因爲傳參是同樣的用法,這裏用insert做爲例子,User中有屬性name和age --> <insert id="insertUser" parameterType="work.pojo.User" > INSERT INTO USER(name,age) VALUES (#{name},#{age}); </insert>
%
這個東西在哪裏存:
#{參數名}
來獲取參數。
sqlSession.selectList("user.getUserByName","%唐%");
,SQL中使用#{參數名}
:SELECT * FROM USER WHERE name LIKE #{name};
${參數名}
能夠用來字符串拼接,它能夠在將字符串包裹的${參數名}
轉成對應的數據,但對於非POJO類型的參數名只能爲value,對於POJO類型的就只能使用POJO類型的屬性了。
SELECT * FROM USER WHERE name LIKE '%${value}%';
SELECT * FROM USER WHERE name LIKE CONCAT('%',#{name},'%')
SELECT * FROM USER WHERE id = #{id}
的返回值應該是一個User類。假設數據表中的字符名爲username,但對象中的屬性名爲name,那麼怎麼對應上呢?
<!-- SELECT id,username ,age FROM USER WHERE id = #{id} --><!--因爲字符名與屬性名不徹底相同,自動映射失敗--> <!-- 使用下面的語句,利用別名 --> SELECT id,username as name ,age FROM USER WHERE id = #{id}
使用resultMap,顯式對應:property是類對象的屬性名,column是字段名
<resultMap type="work.pojo.User" id="userMap"> <id property="id" column="id" /> <!-- 手動把字段名與屬性對應上 --> <result property="name" column="username" /> <result property="age" column="age"/> </resultMap>
resultMap用來顯式定義數據封裝規則,resultMap把數據表的數據與對象的屬性一一對應起來,若是SQL語句的返回結果類型使用了resultMap,這樣MyBatis就會根據resultMap中的規則來封裝返回的數據。
result標籤:用來定義普通字段的映射關係。
<!-- 定義resultMap --> <resultMap type="work.pojo.User" id="userMap"> <!--id標籤把數據表中的id字段與User類中的id屬性對應起來 --> <id property="id" column="id" /> <result property="name" column="name" /> <result property="age" column="age"/> </resultMap> <!-- 引用resultMap --> <select id="getUserById" parameterType="int" resultMap="userMap"> SELECT * FROM USER WHERE id = #{id1} </select>
resultMap還與關聯查詢有關係,關聯查詢依靠resultMap來定義映射關係。這留到後面講。
insert用來定義插入語句
屬性:
使用說明:增刪改三種語句默認是不提交,要commit
<insert id="insertUser" parameterType="work.pojo.User" > INSERT INTO USER(name,age) VALUES (#{name},#{age}); </insert>
主鍵返回問題,有時候咱們但願插入了一條記錄後,獲取到它的ID來處理其餘業務,那麼這時候咱們怎麼獲取它的主鍵呢?下面列舉兩種方法:
JDBC式:在insert標籤上配置useGeneratedKeys和keyProperty屬性,useGeneratedKeys用來代表這個數據庫是否是自增加id的,因此這個獲取主鍵的方式不適用與Oracle。keyProperty用來指明返回的主鍵值存儲到哪一個屬性中。
<insert id="save" parameterType="work.domain.User" useGeneratedKeys="true" keyProperty="userId" > insert into user(userName,password,comment) values(#{userName},#{password},#{comment}) </insert>
數據庫式:利用數據庫的函數來獲取主鍵,keyProperty用來指明返回的主鍵值存儲到哪一個屬性中。order用來指定執行的順序,到底是插入前獲取--BEFORE,仍是插入後獲取--AFTER。resultType用來指明返回主鍵的數據類型。
<insert id="save" parameterType="work.domain.User" > <selectKey resultType="java.lang.Long" order="AFTER" keyProperty="userId"> SELECT LAST_INSERT_ID() </selectKey> insert into user(userName,password) values(#{userName},#{password}) </insert>
屬性與insert差很少
MyBatis因爲是根據SQL去修改,因此它不會發生覆蓋修改問題(Hibernate基於對象來查詢,對於沒有設置值的屬性也會修改到數據表中,因此Hibernate中一般都是先查詢後修改)
<update id="updateUser" parameterType="com.pojo.User"> UPDATE USER SET username = #{username} WHERE id = #{id} </update>
屬性與insert差很少
<delete id="deleteUser" parameterType="int"> DELETE FROM user WHERE `id` = #{id1} </delete>
<sql id="userCols"> id,name,age </sql> <!-- 開始引用 --> <select id="getUserById" parameterType="int" resultType="work.pojo.User"> <!-- SELECT id,name,age FROM USER WHERE id = #{id1} --> SELECT <include refid="userCols"></include> FROM USER WHERE id = #{id1} </select>
上面學過了映射文件裏面定義SQL,那麼下面來了解一下怎麼使用這些SQL語句。發送SQL的方式有兩種,一種是使用SqlSession來發送,一種是使用Mapper來發送。
1.建立映射文件,這裏假設爲user.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"> <mapper namespace="user"> <select id="getUserById" parameterType="int" resultType="user" > SELECT id,name,age FROM USER WHERE id = #{id} </select> </mapper>
2.在配置文件中引入映射文件:【因爲沒有怎麼講mybatis配置文件,你能夠先按照基礎示例裏面來修改】
<mappers> <!-- 導入映射文件 --> <mapper resource="work/pojo/user.xml"/> </mappers>
3.獲取SqlSession,並使用SqlSession調用對應的SQL:
@Test public void test3() throws IOException { SqlSessionFactoryBuilder sfb=new SqlSessionFactoryBuilder(); InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sessionFactory = sfb.build(inputStream); SqlSession sqlSession = sessionFactory.openSession(); //根據SQL ID來發送SQL,第二個是傳給SQL的參數。 User user = sqlSession.selectOne("user.getUserById",3); System.out.println(user); sqlSession.close(); }
1.首先建立一個接口,
package work.pojo; public interface UserMapper { public User getUserById(int id); }
2.建立映射文件(這裏假設爲UserMapper.xml),映射文件要求namespace必需是接口的全路徑名:
<!-- namespace要寫接口的全限定名 --> <mapper namespace="work.pojo.UserMapper"> <!--注意返回類型和入參類型要與接口的一致 --> <select id="getUserById" parameterType="int" resultType="work.pojo.User" > SELECT id,name,age FROM USER WHERE id = #{id} </select> </mapper>
3.在配置文件中引入Mapper:
<mappers> <!-- 導入映射文件 --> <!--既能夠導入接口,也能夠導入映射文件 --> <!--<mapper resource="work/pojo/UserMapper.xml"/> --> <mapper class="work.pojo.UserMapper"/> </mappers>
4.在代碼中利用sqlSession獲取接口的Mapper,並使用Mapper發送SQL(調用對應的接口方法就是發送對應SQL):【這裏提一下,雖然獲取的是接口,但因爲遵循了開發規範,Mybatis會幫忙建立一個這個接口的實現類,因此實質返回的是一個實現類對象】
@Test public void test4() throws IOException { SqlSessionFactoryBuilder sfb=new SqlSessionFactoryBuilder(); InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sessionFactory = sfb.build(inputStream); SqlSession sqlSession = sessionFactory.openSession(); //根據接口.class來獲取mapper UserMapper mapper = sqlSession.getMapper(UserMapper.class); //調用接口的方法就是調用方法對應的SQL。 User user = mapper.getUserById(3); System.out.println(user); sqlSession.close(); }
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
傳入一個UserMapper.class就能夠獲取一個可以調用方法的mapper,咱們僅僅定義了UserMapper接口,爲何能獲取一個可以獲取一個可以調用方法的mapper呢?由於mybatis底層自動幫咱們去建立這個接口的實現類了,因爲咱們遵循了設計規範,mybatis可以很容易地瞭解該如何去建立實現類。建立完實現類後,返回一個實現類的對象。SqlSession方式:
Mapper方式:因爲UserMapper接口已經包含原來的UserDao的功能了,而且不須要自定義實現類,因此這裏能夠省去DAO層。
兩種方式比較:
mapper.getRole(1L)
。配置文件的dtd約束配置信息並無寫在jar包中,因此咱們不能從依賴包中查到,只能依靠官方文檔來獲取,下載的包中的mybatis-3.4.5.pdf中就有,在 Getting started中能夠複製dtd約束。
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
標籤的出現的順序必須按照順序。
<configuration><!-- configuration是配置文件的頂級標籤 --> <!-- properties用於配置一些參數,這些參數能夠被引用到下面的其餘配置中,至關於properties文件 --> <properties></properties> <!-- setting用於配置一些mybatis底層相關的屬性,好比緩存 --> <settings></settings> <!--typeAliases 用於配置類型命名 --> <typeAliases></typeAliases> <!-- typeHandlers用於配置類型處理器 --> <typeHandlers></typeHandlers> <!-- objectFactory用於配置對象工廠 --> <objectFactory type=""></objectFactory> <!--plugins用於配置插件 --> <plugins></plugins> <!-- environments配置不一樣的數據庫鏈接環境 --> <environments default=""> <environment id=""> <!--environment用於配置數據庫鏈接環境 --> <!-- transactionManager用於配置事務管理器 --> <transactionManager type=""></transactionManager> <!--dataSource用於配置數據源 --> <dataSource type=""></dataSource> </environment> </environments> <!-- databaseIdProvider是數據庫產商標識 --> <databaseIdProvider type=""></databaseIdProvider> <!-- mappers用於配置映射器 --> <mappers></mappers> </configuration>
上面的標籤中,plugins涉及插件,是偏向底層的內容,若是不瞭解mybatis運行原理,那麼可能會比較晦澀,這會留到另一篇博文再講述(若是有空的話)。【databaseIdProvider和objectFactory不講述】
下面主要講properties、settings、typeAliases、typerHandler、environments、mappers。
environments用來配置多個數據庫鏈接環境,每個環境都使用environment標籤來定義。(不一樣的環境能夠定義不一樣的數據庫鏈接信息)
<environments default="development">省略environment配置</environments>
表明默認使用id="development"的環境。sqlSession.comit()
來進行事務提交。<transactionManager type="JDBC" ></transactionManager>
<environments default="development"> <!-- environment用來定義數據庫環境,environments用來定義多個environment --> <environment id="development"> <!-- 配置事務管理,使用jdbc事務管理 --> <transactionManager type="JDBC" /> <!-- 配置數據庫鏈接池 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mybatis2" /> <property name="username" value="root" /> <property name="password" value="123456" /> </dataSource> </environment> </environments>
properties標籤的做用相似properties文件,properties標籤能夠導入properties配置文件,也能夠直接使用子標籤property來配置參數。properties標籤中配置的參數能夠在後面的其它屬性配置中引用。
使用方式:
用properties標籤導入配置文件:
<!-- 示例 --> <properties resource="jdbc.properties"></properties>導入後,根據
${鍵名}
來引用配置文件中配置的參數,例如在配置數據源的時候:<property name="driver" value="${jdbc.driverClass}" />
用properties標籤訂義property變量,定義後也可使用${鍵名}
來引用。
設置參數:
<properties> <property name="db.driver" value="com.mysql.jdbc.Driver"/> <property name="db.url" value="jdbc:mysql://localhost:3306/mybatis2"/> <property name="db.user" value="root"/> <property name="db.password" value="123456"/> </properties>
引用參數:
<environment id="test"> <!-- 配置事務管理,使用jdbc事務管理 --> <transactionManager type="JDBC" /> <!-- 配置數據庫鏈接池 --> <dataSource type="POOLED"> <property name="driver" value="${db.driver}" /> <property name="url" value="${db.url}" /> <property name="username" value="${db.user}" /> <property name="password" value="${db.password}" /> </dataSource> </environment>
爲了分清楚配置的屬性的做用,一般都會使用點分法來定義變量,如可使用db.xxx表明這個配置與數據庫相關。【固然,不使用點分法也能夠】
https://blog.csdn.net/u014231523/article/details/53056032
,好像寫的算靠譜了。typeAliases一般用來別名,定義別名後,能夠把很長的名字定義成一個較短的名字,例如類的全限定名(qualified name)很長時,能夠用一個別名來表明這個類路徑。
別名可使用在映射文件中,一般能夠把類的全限定名定義成別名,這樣就能夠簡寫了。
別名分爲系統定義別名和自定義別名
系統定義別名主要是一些數據類型別名,因此要注意定義sql的入參類型和結果類型,SQL語句的結果類型resultType定義成int的時候,返回的結果應該用Integer類型的變量存儲
別名 | 映射的類型 |
---|---|
_byte |
byte |
_long |
long |
_short |
short |
_int |
int |
_integer |
int |
_double |
double |
_float |
float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
自定義別名:
可使用typeAlias標籤來定義別名:
<typeAliases> <!-- alias的值是別名,type的值是要定義別名的名字 --> <typeAlias type="work.pojo.User" alias="user"/> </typeAliases>
別名包掃描:
<typeAliases> <!-- 整個包下的類都被定義別名,別名爲類名,不區分大小寫--> <package name="work.pojo"/> <!--這樣pojo下的類都被定義成了別名,例如work.pojo.User能夠簡寫成user --> </typeAliases>
別名是忽略大小寫的,因此別名user,你既可使用user來引用,也可使用User來引用。
typeHandler是用來處理類型轉換問題的,從數據庫中獲取的數據要想裝入到對象中,勢必要通過類型轉換,比如MyBatis必須知道如何將varchar轉成String。對於常見的類型轉換,MyBatis已經幫咱們定義了很多類型轉換器,下面給出常見的。
數據庫數據類型 | Java類型 | 類型轉換器 |
---|---|---|
CHAR, VARCHAR |
String | StringTypeHandler |
BOOLEAN | Boolean | BooleanTypeHandler |
SMALLINT |
Short |
ShortTypeHandler |
INTEGER |
Integer |
IntegerTypeHandler |
FLOAT |
Float |
FloatTypeHandler |
DOUBLE |
Double |
DoubleTypeHandler |
因爲MyBatis的轉換器已經可以解決大部分問題了,因此這裏不講怎麼自定義轉換器,有興趣的能夠自查。
mappers是用來引入映射器(映射文件)的,有了映射器,Mybatis纔可以管理到在映射文件中定義的SQL。
引入方式:
導入配置文件,經過配置文件的路徑名導入:
<mappers> <!-- 第一種方式,根據映射文件路徑--> <mapper resource="work/pojo/user.xml"/> </mappers>
使用mapper方式開發時,因爲映射文件與mapper對應,也能夠經過mapper的全限定名導入:
【要求映射文件與mapper處於同一目錄,並且映射文件的文件名與要mapper名一致】
<mappers> <!-- 對下面的配置,要求映射配置文件的文件名爲UserMapper.xml;要求UserMapper.xml與UserMapper處於同一目錄下--> <mapper class="work.mapper.UserMapper"/> </mappers>
使用mapper方式開發時,因爲映射文件與mapper對應,也能夠經過掃描mapper所在的包來導入:
【要求映射文件與mapper處於同一目錄,並且映射文件的文件名與要mapper名一致】
<mappers> <!-- 第三種方式,包掃描器: 一、映射文件與接口同一目錄下 二、映射文件名必需與接口文件名稱一致 --> <package name="work.mapper"/> </mappers>
下面的SQL語句,若是調用的時候不傳參,將獲得SELECT * FROM USER WHERE age = null;
<select id="getUserByAge" parameterType="int" resultType="work.pojo.User"> SELECT * FROM USER WHERE age = #{age}; </select>
利用if標籤解決問題:
<select id="getUserByAge" parameterType="int" resultType="work.pojo.User"> SELECT * FROM USER <if test="age!=null "> WHERE age = #{age} </if> </select>
where主要用於處理多個判斷條件的拼接。在where A條件 and B條件可能須要判斷一下A和B的合法性,若是僅僅使用if標籤那麼可能會致使where、and字符串重複,而where會自動處理多餘的and和where,還會自動加上where。
<select id="getUserByAgeOrName" parameterType="work.pojo.User" resultType="work.pojo.User"> SELECT * FROM USER <where> <if test="age!=null "> and age = #{age} </if> <if test="name!=null"> and name like '%${name}%' </if> </where> </select>
where標籤能夠解決查詢條件中的where問題,但若是對一個對象進行update時,如何判斷傳入的set值是否爲空呢?可使用if來進行判斷,而後再使用set標籤解決條件字符串重複問題,set標籤能夠去除多餘的逗號。
<update id="updateUser" parameterType="work.pojo.User"> UPDATE USER SET name=#{name}, age=#{age} where id=#{id} </update>
<update id="updateUser" parameterType="work.pojo.User"> UPDATE USER <set> <if test="name!=null">name=#{name},</if> <if test="age!=null">age=#{age}</if> </set> where id=#{id} </update>
<select id="getUserByAgeCollection" parameterType="List" resultType="work.pojo.User"> SELECT * FROM USER WHERE <foreach item="age" collection="list" open="age IN(" separator="," close=")"> #{age} </foreach> </select>
以一個部門對應一個經理爲例。
建立一個POJO類,用鏈接查詢語句查詢出兩個表的數據,經過resultType封裝到一個POJO類中。
步驟:
1.首先建立一個POJO類,要求包含了部門信息和經理信息(若是你不想重複定義屬性,也能夠選擇繼承單個類的信息繼承兩個類,這裏考慮到有選擇地查詢字段因此不繼承):
package work.pojo; public class Department_Manager { //部門的信息 private Integer did; private String department_name; //經理的信息 private Integer mid; private String name; private Double salary; public Integer getDid() { return did; } public void setDid(Integer did) { this.did = did; } public String getDepartment_name() { return department_name; } public void setDepartment_name(String department_name) { this.department_name = department_name; } public Integer getMid() { return mid; } public void setMid(Integer mid) { this.mid = mid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getSalary() { return salary; } public void setSalary(Double salary) { this.salary = salary; } @Override public String toString() { return "Department_Manager [did=" + did + ", 部門名=" + department_name + ", mid=" + mid + ", 經理名="+ name + ", 工資=" + salary + "]"; } }
數據表的建立(要注意,因爲存在關係,那麼兩個表之間確定有一個字段用於創建關聯,在POJO類中能夠沒有這個字段,但表中必定要有,由於SQL語句依靠這個來查詢):
use mybatis2; create table department( did int primary key auto_increment, department_name varchar(20) ); create table manager( mid int primary key auto_increment, name varchar(20), salary double(7,2), did int, foreign key(did) references department(did) --這裏用外鍵關聯 ); insert into department values(null,'開發部'),(null,'市場部'); insert into manager values(null,'張三',20000.00,1),(null,'李四',20000.00,2);
2.編寫SQL語句:【這裏使用Mapper方式】
定義接口:
package work.pojo; public interface UserMapper { public Department_Manager[] getDepartmentManager(); }
建立映射文件:
<?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="work.pojo.UserMapper"> <select id="getDepartmentManager" resultType="work.pojo.Department_Manager" > SELECT d.did,d.department_name, m.mid,m.name,m.salary FROM department d LEFT JOIN manager m ON d.did = m.did </select> </mapper>
3.編寫測試方法:
@Test public void test5() throws IOException { SqlSessionFactoryBuilder sfb=new SqlSessionFactoryBuilder(); InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sessionFactory = sfb.build(inputStream); SqlSession sqlSession = sessionFactory.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Department_Manager[] departmentManager = mapper.getDepartmentManager(); for (Department_Manager department_Manager : departmentManager) { System.out.println(department_Manager); } sqlSession.close(); }
因此第一種方式是把數據封裝到一個包含了多個表的全部字段的POJO對象的方式。若是有多個表,有多種關係的話,第一種方式會顯得麻煩複雜。
建立一個在部門類裏面添加一個經理類對象,用鏈接查詢語句查詢出兩個表的數據,經過resultMap把查出來的數據封裝到部門類中。
步驟:
1.建立經理類,建立部門類,在部門類中添加一個經理類對象。
經理類:
java package work.pojo; public class Manager { private Integer mid; private String name; private Double salary; private Integer did; //did是部門表的主鍵,你能夠不定義,由於關注點在部門,你也能夠定義成一個部門對象。 public Integer getMid() { return mid; } public void setMid(Integer mid) { this.mid = mid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getSalary() { return salary; } public void setSalary(Double salary) { this.salary = salary; } public Integer getDid() { return did; } public void setDid(Integer did) { this.did = did; } @Override public String toString() { //因爲沒有給did封裝數據,因此這裏不打印did return "Manager [mid=" + mid + ", name=" + name + ", salary=" + salary + "]"; } }
部門類:
package work.pojo; public class Department { private Integer did; private String department_name; //經理的映像 private Manager manager; public Integer getDid() { return did; } public void setDid(Integer did) { this.did = did; } public String getDepartment_name() { return department_name; } public void setDepartment_name(String department_name) { this.department_name = department_name; } public Manager getManager() { return manager; } public void setManager(Manager manager) { this.manager = manager; } @Override public String toString() { return "Department [did=" + did + ", department_name=" + department_name + ", manager=" + manager + "]"; } }
2.定義映射文件和接口:
定義接口:
package work.pojo; public interface UserMapper { public Department_Manager[] getDepartmentManager2(); }
建立映射文件,使用resultMap定義多表關聯映射規則:
<?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="work.pojo.UserMapper"> <resultMap type="work.pojo.Department" id="department_manager"> <id property="did" column="did" /> <result property="department_name" column="department_name" /> <!--association用來處理對象中存在另外一個類的對象的狀況, property是對象中另外一個類的對象變量名,javaType是另外一個類的全限定名 標籤裏面使用id和result來映射數據與另外一個類的對象的關係。 --> <association property="manager" javaType="work.pojo.Manager"> <id property="mid" column="mid"/> <result property="name" column="name" /> <result property="salary" column="salary"/> <!-- 這裏要注意不要封裝外鍵字段,由於咱們這裏的經理表的外鍵是did,部門表主鍵是did,會命名衝突;因爲這裏沒封裝數據給經理類的did,因此經理類的did是沒有數據的;若是你想給經理類的did賦值,那麼你應該利用別名,在SQL中令m.did m_did,而後上面使用<result property="did" column="m_did"/> --> </association> </resultMap> <select id="getDepartmentManager2" resultMap="department_manager" > SELECT d.did,d.department_name, m.mid,m.name,m.salary FROM department d LEFT JOIN manager m ON d.did = m.did </select> </mapper>
3.編寫測試方法:
@Test public void test6() throws IOException { SqlSessionFactoryBuilder sfb=new SqlSessionFactoryBuilder(); InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sessionFactory = sfb.build(inputStream); SqlSession sqlSession = sessionFactory.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Department[] departments = mapper.getDepartmentManager2(); for (Department department : departments) { System.out.println(department); } sqlSession.close(); }
若是採用相似上面一對一的方式一來處理一對多話,一一方的會出現不少次(方式一是封裝查詢的每行記錄,一對多查詢的時候一一方的數據會出現屢次,因此採用方式二來實現一對多)。下面以一個班級能夠有多個學生爲例。
步驟:
1.建立Student類,建立Grade類,在Grade中添加一個由Student對象組成的List:
Student類:
package work.pojo; public class Student { private Integer sid; private String stu_name; public Integer getSid() { return sid; } public void setSid(Integer sid) { this.sid = sid; } public String getStu_name() { return stu_name; } public void setStu_name(String stu_name) { this.stu_name = stu_name; } @Override public String toString() { return "Student [sid=" + sid + ", stu_name=" + stu_name + "]"; } }
Grade類:
package work.pojo; import java.util.List; public class Grade { private Integer gid; private String grade_name; private List<Student> students; public Integer getGid() { return gid; } public void setGid(Integer gid) { this.gid = gid; } public String getGrade_name() { return grade_name; } public void setGrade_name(String grade_name) { this.grade_name = grade_name; } public List<Student> getStudents() { return students; } public void setStudents(List<Student> students) { this.students = students; } @Override public String toString() { return "Grade [gid=" + gid + ", grade_name=" + grade_name + ", students=" + students + "]"; } }
2.建立數據表,插入測試數據:
create table grade( gid int primary key auto_increment, grade_name varchar(20) ); create table student( sid int primary key auto_increment, stu_name varchar(20), gid int, foreign key(gid) references grade(gid) ); insert into grade values(null,"python班"),(null,'Java班'); insert into student values(null,'張三',1),(null,'李四',1),(null,'王五',2),(null,'趙六',2);
3.建立mapper接口和映射文件:
接口:
package work.pojo; public interface UserMapper { public Grade[] getGradeStudent(); }
映射文件:
<?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="work.pojo.UserMapper"> <resultMap type="work.pojo.Grade" id="grade_student_map"> <id property="gid" column="gid"/> <result property="grade_name" column="grade_name"/> <!-- collection用來處理一個類中含有其餘類的集合時的數據映射(一對多) property是集合的變量名,ofType是集合元素的全限定名, collection內使用id和result創建映射關係 --> <collection property="students" ofType="work.pojo.Student" > <id property="sid" column="sid"/> <result property="stu_name" column="stu_name" /> </collection> </resultMap> <select id="getGradeStudent" resultMap="grade_student_map"> SELECT g.gid,g.grade_name, s.sid,s.stu_name FROM grade g LEFT JOIN student s ON g.gid = s.gid </select> </mapper>
4.編寫測試方法:
@Test public void test7() throws IOException { SqlSessionFactoryBuilder sfb=new SqlSessionFactoryBuilder(); InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sessionFactory = sfb.build(inputStream); SqlSession sqlSession = sessionFactory.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Grade[] gradeStudent = mapper.getGradeStudent(); for (Grade grade : gradeStudent) { System.out.println(grade); } sqlSession.close(); }
因爲多對多太過複雜,Mybatis不支持多對多,Mybatis選擇使用兩個一對多來實現多對多。下面以一名學生能夠選多門課,一門課能夠被多個學生選爲例。【多對多關係模型是兩方都有對方的數據,兩方都能查詢到對方的數據,因此咱們使用一對多的時候,能向兩方的對象中都裝入數據,就能夠達到多對多的效果;但有一點效果不能達到,(以例子講解)課程對象中的學生集合沒有與課程對象創建上關係,但從業務需求來講一般不關注另一方的關係(若是關注,從學生一方查詢便可,爲何要使用課程中的學生對象?),因此這個缺點也不算缺點。另外,下面也會講一下解決這個問題的方法。】
步驟:
1.建立Cource類,建立SchoolChild類,分別在兩個類中建立對方類的集合:【這裏要注意toString問題,若是A的toString包含B,B包含A,那麼會死循環。】
Cource類:
package work.pojo; import java.util.List; public class Cource { private Integer cid; private String cource_name; private List<SchoolChild> schoolchilds; public Integer getCid() { return cid; } public void setCid(Integer cid) { this.cid = cid; } public String getCource_name() { return cource_name; } public void setCource_name(String cource_name) { this.cource_name = cource_name; } public List<SchoolChild> getSchoolchilds() { return schoolchilds; } public void setSchoolchilds(List<SchoolChild> schoolchilds) { this.schoolchilds = schoolchilds; } }
SchoolChild類:
package work.pojo; import java.util.List; public class SchoolChild { private Integer sid; private String stu_name; private List<Cource> cources; public Integer getSid() { return sid; } public void setSid(Integer sid) { this.sid = sid; } public String getStu_name() { return stu_name; } public void setStu_name(String stu_name) { this.stu_name = stu_name; } public List<Cource> getCources() { return cources; } public void setCources(List<Cource> cources) { this.cources = cources; } }
2.建立表(注意有中間表):
create table cource( cid int primary key auto_increment, cource_name varchar(20) ); create table schoolChild( sid int primary key auto_increment, stu_name varchar(20) ); create table cource_schoolChild( cid int, sid int, foreign key(cid) references cource(cid), foreign key(sid) references schoolChild(sid) ); insert into cource values(null,"python"),(null,'Java'); insert into schoolChild values(null,'張三'),(null,'李四'),(null,'王五'); insert into cource_schoolChild values(1,1),(1,2),(1,3),(2,1),(2,3);
3.建立接口和映射文件:
接口:
package work.pojo; public interface UserMapper { public Cource[] getCource(); public SchoolChild[] getSchoolChild(); }
映射文件:【難點是sql語句,其餘的resultMap與一對多的同樣】
<?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="work.pojo.UserMapper"> <resultMap type="work.pojo.Cource" id="cource_schoolchild_map"> <id property="cid" column="cid" /> <result property="cource_name" column="cource_name" /> <collection property="schoolchilds" ofType="work.pojo.SchoolChild"> <id property="sid" column="sid" /> <result property="stu_name" column="stu_name" /> </collection> </resultMap> <select id="getCource" resultMap="cource_schoolchild_map"> select t1.cid,t1.cource_name, t3.sid,t3.stu_name from cource t1 left join cource_schoolChild t2 on t1.cid=t2.cid left join schoolChild t3 on t2.sid=t3.sid; </select> <resultMap type="work.pojo.SchoolChild" id="schoolchild_cource_map"> <id property="sid" column="sid" /> <result property="stu_name" column="stu_name" /> <collection property="cources" ofType="work.pojo.Cource"> <id property="cid" column="cid" /> <result property="cource_name" column="cource_name" /> </collection> </resultMap> <select id="getSchoolChild" resultMap="schoolchild_cource_map"> select t1.cid,t1.cource_name, t3.sid,t3.stu_name from cource t1 left join cource_schoolChild t2 on t1.cid=t2.cid left join schoolChild t3 on t2.sid=t3.sid; </select> </mapper>
4.編寫測試方法:
@Test public void test8() throws IOException { SqlSessionFactoryBuilder sfb=new SqlSessionFactoryBuilder(); InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sessionFactory = sfb.build(inputStream); SqlSession sqlSession = sessionFactory.openSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Cource[] cources = mapper.getCource(); for (Cource cource : cources) { System.out.println(cource); } System.out.println("---分隔線---"); SchoolChild[] schoolChilds = mapper.getSchoolChild(); for (SchoolChild schoolChild : schoolChilds) { System.out.println(schoolChild); }
5.測試結果:
Cource [cid=1, cource_name=python, schoolchilds=[SchoolChild [sid=1, stu_name=張三, cources=null], SchoolChild [sid=2, stu_name=李四, cources=null], SchoolChild [sid=3, stu_name=王五, cources=null]]] Cource [cid=2, cource_name=Java, schoolchilds=[SchoolChild [sid=1, stu_name=張三, cources=null], SchoolChild [sid=3, stu_name=王五, cources=null]]] ---分隔線--- SchoolChild [sid=1, stu_name=張三, cources=[Cource [cid=1, cource_name=python, schoolchilds=null], Cource [cid=2, cource_name=Java, schoolchilds=null]]] SchoolChild [sid=2, stu_name=李四, cources=[Cource [cid=1, cource_name=python, schoolchilds=null]]] SchoolChild [sid=3, stu_name=王五, cources=[Cource [cid=1, cource_name=python, schoolchilds=null], Cource [cid=2, cource_name=Java, schoolchilds=null]]]
在上面的測試結果中,課程對象中查出的學生對象的課程對象是null,這是由於沒有封裝上,下面能夠提供一種方法來解決上面這個問題,但要注意--這個問題是解決不了的:這是由於MyBatis是面向SQL的,你定義了映射規則它才能幫你封裝,MyBatis對於對象與對象中嵌套對象的關係並不瞭解,它不知道怎麼作,只有你進行了封裝定義纔可以給嵌套對象封裝數據。若是你在resultMap的collection中嵌套一個collection就能夠對嵌套對象中的嵌套對象封裝數據,但嵌套對象中的嵌套對象的嵌套對象裏的對象仍是會空的。
<?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="work.pojo.UserMapper"> <resultMap type="work.pojo.Cource" id="cource_schoolchild_map"> <id property="cid" column="cid" /> <result property="cource_name" column="cource_name" /> <collection property="schoolchilds" ofType="work.pojo.SchoolChild"> <id property="sid" column="sid" /> <result property="stu_name" column="stu_name" /> <!-- 給嵌套對象裏面的嵌套對象封裝數據 --> <collection property="cources" ofType="work.pojo.Cource"> <id property="cid" column="cid" /> <result property="cource_name" column="cource_name" /> </collection> </collection> </resultMap> <select id="getCource" resultMap="cource_schoolchild_map"> select t1.cid,t1.cource_name, t3.sid,t3.stu_name from cource t1 left join cource_schoolChild t2 on t1.cid=t2.cid left join schoolChild t3 on t2.sid=t3.sid; </select> <!-- 省略SchoolChild的。 --> </mapper>
<mapper namespace="work.mapper.ProductMapper"> <resultMap type="work.domain.Product" id="product_category"> <id property="pid" column="pid"/> <result property="pname" column="pname"/> <result property="price" column="price"/> <result property="pimage" column="pimage"/> <result property="pdesc" column="pdesc"/> <!-- 這裏是多表查詢操做,這裏商品裏面有一個商品分類外鍵 --> <association property="category" javaType="work.domain.Category"> <result property="category_name" column="category_name"/> </association> </resultMap> <select id="findAll" resultMap="product_category"> select p.pid,p.pname,p.price,p.pimage,p.pdesc, c.cid,c.category_name from product p left join category c on p.cid = c.cid; </select> <insert id="save" parameterType="work.domain.Product"> insert into product(pname,price,pimage,pdesc,cid) values( #{pname},#{price},#{pimage},#{pdesc},#{category.cid} ); </insert> </mapper>
@Test public void test9() throws IOException { SqlSessionFactoryBuilder sfb=new SqlSessionFactoryBuilder(); InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sessionFactory = sfb.build(inputStream); SqlSession sqlSession = sessionFactory.openSession(); //根據接口.class來獲取mapper UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.getUserById(3); User user2 = mapper.getUserById(3); System.out.println(user); System.out.println(user==user2); sqlSession.close(); }
在select\delete\insert標籤 中,有一個flushCache屬性:設置查詢以後是否刪除本地緩存和二級緩存。
整合第三方鏈接池,固然要引入依賴包啦。這裏就很少講了,就是第三方鏈接池的依賴包。
首先須要定義一個數據源工廠,這個工廠要繼承UnpooledDataSourceFactory,在構造函數中返回須要使用的鏈接池對象
package work.dataSource; import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory; import com.mchange.v2.c3p0.ComboPooledDataSource; public class C3P0DataSourceFactory extends UnpooledDataSourceFactory { public C3P0DataSourceFactory(){ this.dataSource=new ComboPooledDataSource(); } }
而後在mybatis-config.xml中配置使用第三方鏈接池:
<!-- type裏填剛纔定義的鏈接池工廠的全限定名 --> <dataSource type="work.dataSource.C3P0DataSourceFactory"> <!-- 下面的屬性名要按照鏈接池自身的規則來配置,好比c3p0的驅動參數是driverClass --> <property name="driverClass" value="com.mysql.jdbc.Driver" /> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis2" /> <property name="user" value="root" /> <property name="password" value="123456" /> <property name="idleConnectionTestPeriod" value="60" /> <property name="maxPoolSize" value="20" /> <property name="maxIdleTime" value="600" /> </dataSource>
如今沒有寫的內容:
不寫,有興趣自查的內容: