上篇SSM框架環境搭建篇,演示了咱們進行web開發必不可少的一些配置和準備工做,若是這方面還有疑問的地方,能夠先參考上一篇「SSM框架開發web項目系列(一) 環境搭建篇」。本文主要介紹MyBatis的基礎內容,包括基本概念、開發步驟、使用實例等。提及MyBatis,工做中作過SSH/SSM相關Web開發的或者正在學習MyBatis的人或多或少都會接觸到相似「MyBatis和Hibernate有什麼區別?」,「MyBatis和Hibernate哪一個更好?」,「爲何Mybatis用的人愈來愈多?」等等...記得面試問題,區別問的最多,有次被面試官問到更喜歡用哪個?明明已經知道這個公司介紹用的是SSM了,我答了個Hibernate,並說先用的也是Hibernate,或許初戀的感受過於深入吧...誰好誰差這種主觀性問題,咱們不爭論,可是不容質疑的是二者都爲企業級開發作出巨大貢獻。同時,帶着問題和求知慾去學習每每會讓學習效率大大提升,由於許多問題在困惑你的同時,也爲你指引了方向。就正如你得會用它,理解它了,才知道它在某方面爲何會不足。html
早些時候,Apache有一個開源項目iBatis,後來更名了叫Mybatis,因此咱們在網上有時候會看到一些早期的文章有時候看到iBatis,實際上是同一個東西。同時,你們能夠看下MyBatis源碼工程結構,以下圖,也能發現這個問題。java
MyBatis是一個半自動-ORM-持久層框架,下面分別介紹這三個概念,若是瞭解的的能夠直接跳過以節省時間。mysql
首先持久層比較好理解,就是針對數據庫的各類操做持久化層面,咱們用jdbc也能夠對數據庫中表進行增刪可查;WEB開發分層結構中,相似的還有業務層、控制層,MyBatis所作用的層,主要是用於與數據庫打交道。web
其次ORM(Object Relational Mapping,對象關係映射)是一種技術,也是思想,若是用過jdbc的原生方式操做數據的應該都知道,其中各類獲取和更新的操做都已有相關的API了,可是這個過程實在太繁瑣,獲取鏈接、構造語句、發送SQL和接收數據、最後是處理數據和關閉流等等...實際的工做開發中,顯然不太適用。也許是有人想到,最麻煩的地方在於獲取數據後的處理過程,爲了簡化這一過程,以Java中面向對象的思惟構造了這一個ORM關係模型,即每張數據表對應一個Java類,數據表中每一條記錄分別對應Java類的一個實體對象,數據表中每一個字段對應Java類中的一個屬性,這樣一來Java中一切皆對象,數據庫裏的東西既然已經對應映射到Java概念中來,咱們再用面向對象的思惟去操做數據庫,就大大簡化了開發流程。面試
最後,解釋半自動,既然有半自動,應該就有全自動,例如Hibernate就是一個全自動的ORM持久層框架,它在創建數據庫和bean對象關係映射模型的同時,提供的api還會幫助咱們自動生成和發送SQL語句去操做數據庫,而MyBatis略有不一樣,它也創建了對象關係映射模型,可是並不會幫助咱們生成SQL語句,須要咱們本身寫SQL語句,很多人可能會以爲別人均可以幫你自動生成了這還要本身寫,不是沒事找事嗎?可是偏偏相反,不少人由於這點喜歡上了MyBatis,靈活且透明,本身動手不解釋。sql
關於MyBatis的學習使用過程當中,依次要注意的四個對象有SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession、Mapper實例。數據庫
1.SqlSessionFactoryBuilderapache
SqlSessionFactoryBuilder是一個類,裏面定義許多重載的build方法,經過build方法能夠獲取SqlSessionFactory對象,即SqlSession工廠實例api
2.SqlSessionFactorysession
SqlSessionFactory是一個接口,看名字應該能明白是SqlSession工廠,裏面定義了許多重載的openSession方法,用於獲取SqlSession對象
3.SqlSession
SqlSession是一個很關鍵的接口,經過它咱們能夠執行發送SQL語句、得到Mapper實例等等。以它的第一個方法爲例, <T> T selectOne(String statement); 方法名很容易理解,獲取數據表的一條記錄(在Java中對應返回一個實體類對象),前面的泛型對應的就是實體類的類型,關於String類型的參數statement,用過原生的JDBC操做數據庫的應該不會陌生,在使用JDBC過程當中,有個Statement對象,經過該對象的相似 ResultSet executeQuery(String sql) throws SQLException; 等方法能夠發送SQL語句,方法裏的字符串類型參數 sql 就是咱們要發送的sql語句,而前面的String statement 一樣也是表明咱們的sql語句。總的來講,selectOne中的statement表明sql語句,JDBC中的statement是能發送sql語句的對象實例,不可混淆。
4.Mapper實例
Mapper實例就是咱們在dao層定義的定義的接口實例,咱們在service層中注入dao對象時關聯的是該接口名,而實際上咱們拿到了該接口實例也就是Mapper實例。而咱們在web開發過程當中,持久層的相關方法都定義在Mapper接口中,因此四個對象裏咱們在前面環境搭建篇比較容易發現的也就是這個Mapper實例所屬接口,即PersonMappr接口。Mapper實例能夠經過SqlSession的getMapper方法得到。
以上爲MyBatis配置文件下節點的結構分佈圖,熟悉DTD的根據org/apache/ibatis/builder/xml下的約束文件mybatis-*-config.dtd也能夠獲取XML規範。
environment(環境)
在開發中,咱們要鏈接到數據庫,每每都須要配置一個數據源,其中包括數據庫url參數,用戶名和密碼等等,另外還有事事務管理器配置。MyBatis中也不例外,在這裏針對一個數據庫的鏈接,有一個environment(環境)與之對應,若是有多個數據庫,咱們能夠在environments下定義多個environment。environment下面經過dataSource和transactionManager的property屬性進行數據源和事務管理器配置。
typeAliases(類型命名)
這個是開發中很實用的配置,前面配置篇中mybatis-config.xml中的<typeAlias alias="person" type="com.mmm.pojo.Person" />,給類綁定別名,而後在其餘地方引用時能夠不用寫類的全名(相似com.xxx.Xxx形式),直接寫別名便可,例如後面personMapper.xml映射文件中<resultMap type="person" id="personResultMap" >,這裏的person別名就表明該類了,若是沒有前面的別名綁定,咱們在全部須要類型type指定com.mmm.pojo.Person的時候,都須要寫全名。另外MyBatis中自己已經綁定了許多相似的別名,在Configuration類的構造中已經預先註冊綁定了相關別名,這也是咱們在用Spring集成開發的配置文件中那些特殊別名能獲得解析的關鍵所在,以下所示
public Configuration() {
typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class); typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class); typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class); typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class); typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class); typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class); typeAliasRegistry.registerAlias("FIFO", FifoCache.class); typeAliasRegistry.registerAlias("LRU", LruCache.class); typeAliasRegistry.registerAlias("SOFT", SoftCache.class); typeAliasRegistry.registerAlias("WEAK", WeakCache.class); typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class); typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class); typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class); typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class); typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class); typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class); typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class); typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class); typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class); typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class); typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class); typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class); languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class); languageRegistry.register(RawLanguageDriver.class); }
mappers(映射器)
<mappers> <mapper resource="com/xxx/xxx/mapper/xxxMapper.xml" /> </mappers>
以上即爲一個映射器配置樣式,經過該配置,Mybatis會找到相應的SQL映射文件(前面環境搭建篇中爲personMapper.xml),下面詳細介紹SQL映射文件。
The true power of MyBatis is in the Mapped Statements(MyBatis真正的力量就在SQL映射語句裏)。這是MyBatis對SQL映射文件做介紹的第一句話,足以體現其重要性,前面說到的半自動的MyBatis須要本身寫SQL語句,這個寫SQL語句的地方就在這裏。
根節點mapper有一個屬性namespace(命名空間),對應的是Mapper接口的全名,經過這個屬性值的設置,MyBatis才能找到該SQL映射文件對象Mapper接口,從而構造相應的Mapper實例對象。
以上爲MyBatis的SQL映射xml文件的元素結構,子節點中還有一個parameterMap,不過已經被廢棄了,就沒畫上去。前面四個,看單詞意思,應該不難理解,分別用於定義增刪改查SQL語句。下面以查詢<select>爲例
<!-- 根據主鍵id查找記錄 --> <select id="selectById" resultType="person"> select * from `TBL_PERSON` where id = #{id} </select>
上面select節點中id爲該節點的惟一標識,與其它節點區分,另外一方面,id名對應咱們的Mapper接口中的方法名,在這裏對應PersonMapper的以下方法:
//根據主鍵id查找Person對象 Person selectById(String id);
因爲是查詢,會有返回數據內容,基於ORM思想,這裏的T_PERSON表返回記錄有一個實體類與之對應,那麼具體對應哪一個實體類怎麼指定?這裏的resultType即指定返回數據對應類型,而且用到了別名,因此這裏其實就是指定了com.mmm.pojo.Person類做爲對應實體類。另外還有一種resultMap定義方式,也能夠指定返回類型,二者不能同時使用,下面會具體講到。若是方法沒有返回值,也能夠不指定類型。
節點中的語句即爲該方法對應的SQL語句,這裏的#{id}表示參數,對應PersonMapper接口中對應方法的參數String id。
另外三種<delete><updata><insert>相似,不過要注意,<insert>做爲插入節點,有幾個特殊屬性,useGeneratedKeys、keyProperty、keyColumn,這三個屬性都是<insert>特有的,也僅對其有效,keyProperty屬性指定數據表主鍵值對應的實體類屬性,這裏爲Person類中的id;keyColumn屬性指定數據表主鍵字段名,這裏爲id;useGeneratedKeys指定是否使用數據表主鍵策略生成的主鍵值,例如在Mysql中主鍵能夠設置自增,而後咱們在插入記錄(或者說是寫SQL語句)時,即便不指定主鍵值,插入也會成功,而且主鍵會自動賦值。爲了以示區別,文中構建示例我會使用MySQL的自增主鍵,而不是以前的隨機字符串做爲主鍵。
<sql>被用來定義可重用的SQL代碼段,能夠包含在其餘語句中。
再來看<resultMap>,以前的Person實例中,數據表的字段名和實體類屬性名都是同樣的,id,name,gender。若是不同的話,咱們再採用以前的寫法就會有問題了,resultMap給咱們提供瞭解決辦法,下面咱們經過完整構建一個Mybatis環境來演示總體內容。
這裏咱們單獨講Mybatis,並未使用Spring集成環境,也並未用到web層的Spring MVC,因此不須要構建web項目。因此首先經過maven新建一個java項目,pom.xml依賴能夠參考前面的SSM環境搭建,最後項目結構大體以下圖所示
數據庫中準備一張員工表TBL_EMP,三個字段:主鍵id自增,姓名emp_name,性別emp_gender,插入若干數據,以下圖
package com.mmm.pojo; //員工實體類 public class Emp { private Integer id; //主鍵 private String name; //員工姓名 private String gender; //員工性別 public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } }
<?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> <!-- 這裏能夠定義類的別名,在mapper.xml文件中應用會方便不少 --> <typeAliases> <typeAlias alias="emp" type="com.mmm.pojo.Emp" /> </typeAliases> <!-- 環境配置 --> <environments default="envir"> <environment id="envir"> <transactionManager type="JDBC"></transactionManager> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://127.0.0.1:3306/ssm?characterEncoding=utf-8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/mmm/mapper/empMapper.xml"/> </mappers> </configuration>
package com.mmm.mapper; import java.util.List; import com.mmm.pojo.Emp; public interface EmpMapper { //新增一個Emp對象 void insert(Emp p); //根據主鍵id刪除Emp對象 void deleteById(Integer id); //修改一個Emp對象 void update(Emp p); //根據主鍵id查找Emp對象 Emp selectById(Integer id); //查找全部Emp對象,返回集合類型 List<Emp> selectAll(); }
<?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"> <!-- namespace命名空間綁定Mapper接口 --> <mapper namespace="com.mmm.mapper.EmpMapper"> <!-- resultMap定義,property對應實體類中屬性,column對應數據表字段名 --> <resultMap type="emp" id="empResultMap" > <id property="id" column="id"></id> <result property="name" column="emp_name"></result> <result property="gender" column="emp_gender"></result> </resultMap> <!-- 新增一條記錄,這裏並未在SQL語句中設置主鍵id值 --> <insert id="insert" parameterType="emp" useGeneratedKeys="true" keyProperty="id" keyColumn="id" > insert into `TBL_EMP`(emp_name,emp_gender) values (#{name},#{gender}) </insert> <!-- 刪除一條記錄 --> <delete id="deleteById"> delete from `TBL_EMP` where id = #{id} </delete> <!-- 更新一條記錄 --> <update id="update" parameterType="EMP"> update `TBL_EMP` set emp_name = #{name}, emp_gender = #{gender} </update> <!-- 查找全部記錄 --> <select id="selectAll" resultMap="empResultMap"> select * from `TBL_EMP` </select> <!-- 根據主鍵id查找記錄 --> <select id="selectById" resultMap="empResultMap"> select * from `TBL_EMP` where id = #{id} </select> </mapper>
package com.mmm.test; import java.io.IOException; import java.io.Reader; import java.util.List; 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 com.mmm.mapper.EmpMapper; import com.mmm.pojo.Emp; public class TestMyBatis { @Test public void testCore() throws IOException { //直接實例SqlSessionFactoryBuilder對象 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //MyBatis配置文件路徑 String path = "mybatis-config.xml"; //經過路徑獲取輸入流 Reader reader = Resources.getResourceAsReader(path); //經過reader構建sessionFactory SqlSessionFactory sessionFactory = builder.build(reader); //獲取SqlSession對象 SqlSession sqlSession = sessionFactory.openSession(); //獲取Mapper實例 EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); //獲取全部記錄並遍歷展現 List<Emp> list = mapper.selectAll(); for(Emp emp:list) { System.out.println("姓名:"+emp.getName()+",性別:"+emp.getGender()); } } }
運行程序成功,結果以下
本文主要介紹了單獨以MyBatis構建數據庫訪問程序的方法步驟,涉及的都是MyBatis基礎和核心的內容,數據庫也是針對的單表操做。MyBatis的關聯查詢、動態SQL、事務管理和Spring集成MyBatis等內容準備梳理一番了以後寫出來。