一、Mybatis的誕生
回顧下傳統的數據庫開發,JDBC和Hibernate是使用最普遍的技術,但這兩種ORM框架都存在一定的局限性:
JDBC:最原生的技術,簡單易學,執行速度快,效率高,適合大數據量的操作,但存在代碼繁瑣,需要關心驅動的加載,連接的關閉等操作,對於分頁等復雜用法,需要自己手動寫代碼實現。
Hibernate:以面向對象的方式設計和訪問,不用寫SQL,不用管底層具體數據庫的語法,但對於多表操作靈活性差,復雜的HQL難寫難理解,執行速度慢,只適合小數據量的操作。
基於上述技術的瓶頸,誕生了一種在這兩者之間找到平衡點的ORM框架,結合它們的優點,摒棄它們的缺點,這就是myBatis,現今myBatis被廣泛的企業所采用。MyBatis 本是apache的一個開源項目iBatis, 2010年這個項目由apache software foundation 遷移到了google code,並且改名為MyBatis 。2013年11月遷移到Github。iBATIS一詞來源於“internet”和“abatis”的組合,是一個基於Java的持久層框架。iBATIS提供的持久層框架包括SQL Maps和Data Access Objects(DAO)
二、Mybatis入門Demo(基於MySQL)
Mybatis程序的運行流程大概如下:
(1)通過Reader對象讀取src目錄下的mybatis.xml配置文件(該文件名稱可自定義,主要用來配置數據源,類型別名以及mapper文件的總配置文件)
(2)通過SqlSessionFactoryBuilder對象創建SqlSessionFactory對象
(3)從當前線程,即ThreadLocal中獲取SqlSession對象
(4)開啟事務(默認開啟)
(5)通過SqlSession對象讀取對應Mapper.xml映射文件中的操作編號,從而讀取sql語句
(6)提交或回滾事務
(7)關閉SqlSession對象,並且分開當前線程與SqlSession對象,讓GC盡早回收
基於上述步驟開始Mybatis入門Demo案例的編寫:
步驟1.引入Mybatis所需jar包依賴
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.3.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.12</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
步驟2.准備數據源db.properties並配置mybatis.xml文件
mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/aa
mysql.username=root
mysql.password=123456
<?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="db.properties"> </properties> <!-- 設置實體類的類型別名 --> <typeAliases> <typeAlias type="com.jyk.mybatis.Student" alias="student"/> </typeAliases> <!-- 設置一個默認的連接環境信息,支持多數據源 --> <environments default="mysql_env"> <!-- 連接環境信息,取一個唯一的編號 --> <environment id="mysql_env"> <!-- mybatis使用的jdbc事務管理方式 --> <transactionManager type="jdbc"> </transactionManager> <!-- mybatis使用連接池方式來獲取鏈接 --> <dataSource type="pooled"> <!-- 配置與數據庫交互的四個屬性 --> <property name="driver" value="${mysql.driver}"/> <property name="url" value="${mysql.url}"/> <property name="username" value="${mysql.username}"/> <property name="password" value="${mysql.password}"/> </dataSource> </environment> </environments>
<mappers> <mapper resource="com/jyk/mybatis/StudentMapper.xml"/> </mappers> </configuration>
步驟3.編寫需要操作的實體類com.jyk.mybatis.Student記錄學生信息
package com.jyk.mybatis; public class Student { private String id; private String name; private String age; private String sex; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Student(String id, String name, String age, String sex) { super(); this.id = id; this.name = name; this.age = age; this.sex = sex; } public Student() { super(); } }
步驟4.配置StudentMapper.xml,配置namespace,需要唯一,一般以需要操作的實體類全路徑為准,也可為其他值。然后是配置實體類與實際表的映射關系resultMap,type屬性:實體全路徑名,可在mybatis.xml文件中統一配置,如在上述mybatis.xml中已配置<typeAlias type="com.jyk.mybatis.Student" alias="student"/>,則此處實體類全路徑可用student代替
注:當實體屬性名與表字段名不一樣時,此處信息必配,若一致,則此處配置可選。
<?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 namespace="studentNamespace"> <!-- resultMap標簽:映射實體與表,非主鍵屬性標簽 type屬性:實體全路徑名,可在mybatis.xml文件中統一配置 id屬性:為實體與表的映射取一個唯一的編號 --> <resultMap type="student" id="studentMap"> <!-- id標簽:映射主鍵屬性 result標簽:映射非主鍵屬性 property屬性:實體屬性名 column屬性:表的字段名 --> <id property="id" column="id"/> <result property="name" column="name"/> <result property="age" column="age"/> <result property="sex" column="sex"/> </resultMap> </mapper>
步驟5.編寫Mybatis通用工具類,通過Reader對象讀取src目錄下的mybatis.xml配置文件,並測試連接
package com.jyk.mybatis.util; import java.io.IOException; import java.io.Reader; import java.sql.Connection; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; /* * MyBatis工具類 */ public class MyBatisUtil { private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>(); private static SqlSessionFactory sqlSessionFactory; //靜態塊加載src目錄下的mybatis配置文件 static{ try { Reader reader = Resources.getResourceAsReader("mybatis.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); } catch (IOException e) { e.printStackTrace(); } } /* * 禁止外界通過new方法創建 */ private MyBatisUtil(){} /* * 獲取sqlsession */ public static SqlSession getSqlSession() { //從當前線程中獲取sqlSession對象 SqlSession sqlSession = threadLocal.get(); //判斷SqlSession對象是否為空 if(sqlSession==null) { //在SqlSessionFactory對象非空的情況下,獲取SqlSession對象 sqlSession = sqlSessionFactory.openSession(); //將SqlSession對象與當前線程綁定在一起 threadLocal.set(sqlSession); } return sqlSession; } /* * 關閉sqlsession與當前線程分開 */ public static void closeSqlSession() { //從當前線程中獲取SqlSession對象 SqlSession sqlSession = threadLocal.get(); if(sqlSession != null) { //關閉SqlSession對象 sqlSession.close(); //分開當前線程與SqlSession對象的關系,目的是盡早進行垃圾回收 threadLocal.remove(); } } /* * 測試方法 */ public static void main(String[] args) { Connection conn = MyBatisUtil.getSqlSession().getConnection(); if(conn==null) { System.out.println("連接為空"); } else { System.out.println("連接不為空"); } } }
步驟6.編寫CRUD語句,在mapper文件中編寫,此處編寫在上述已經配置好實體類映射的StudentMapper.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"> <!-- 名稱空間namespace必須唯一 --> <mapper namespace="studentNamespace"> <!-- resultMap標簽:映射實體與表 type屬性:實體全路徑名 id屬性:為實體與表的映射取一個唯一的編號 --> <resultMap type="student" id="studentMap"> <!-- id標簽:映射主鍵屬性 result標簽:映射非主鍵屬性 property屬性:實體屬性名 column屬性:表的字段名 --> <id property="id" column="id"/> <result property="name" column="name"/> <result property="age" column="age"/> <result property="sex" column="sex"/> </resultMap> <!-- insert標簽:sql插入語句 id屬性:該sql語句的唯一標簽 parameterType:要執行的dao中的方法的參數,如果是類的話,必須使用全路徑名 #{xx}:mybatis特有語法,用來替代jdbc中的?占位符 --> <insert id="add1"> insert into student(id,name,age,sex) values("1","admin","22","男") </insert> <insert id="add2" parameterType="student"> insert into student(id,name,age,sex) values(#{id},#{name},#{age},#{sex}) </insert> <!-- <insert id="add3" parameterType="student"> insert into student(id,name,age,sex) values(#{id},#{name},#{age},#{sex}) </insert> --> </mapper>
步驟7.編寫DAO,利用上述配置完成的文件和寫好的通用工具類MyBatisUtil對學生信息進行增刪該查
package com.jyk.mybatis; import org.apache.ibatis.session.SqlSession; import com.jyk.mybatis.util.MyBatisUtil; public class StudentDao { /* * 增加的方法1 */ public void add1() { SqlSession sqlSession = null; try{ sqlSession = MyBatisUtil.getSqlSession(); //事務開始(默認) //讀取StudentMapper.xml配置文件中的sql語句,對應的sql語句由{名稱空間.sql的id指定} int i = sqlSession.insert("studentNamespace.add1"); System.out.println("本次操作影響了"+i+"行數據"); //事務提交 sqlSession.commit(); }catch(Exception e){ e.printStackTrace(); //事務回滾 sqlSession.rollback(); throw e; }finally{ MyBatisUtil.closeSqlSession(); } } /* * 增加的方法2 */ public void add2(Student stu) { SqlSession sqlSession = null; try{ sqlSession = MyBatisUtil.getSqlSession(); //事務開始(默認) //讀取StudentMapper.xml配置文件中的sql語句 int i = sqlSession.insert("studentNamespace.add2",stu); System.out.println("本次操作影響了"+i+"行數據"); //事務提交 sqlSession.commit(); }catch(Exception e){ e.printStackTrace(); //事務回滾 sqlSession.rollback(); throw e; }finally{ MyBatisUtil.closeSqlSession(); } } /* * 增加的方法3 * 往數據庫添加記錄必須要添加事務,沒有事務添加不進去 */ public void add3(Student stu) { SqlSession sqlSession = null; try{ sqlSession = MyBatisUtil.getSqlSession(); //事務開始(默認) //讀取StudentMapper.xml配置文件中的sql語句 int i = sqlSession.insert("studentNamespace.add3",stu); System.out.println("本次操作影響了"+i+"行數據"); sqlSession.commit(); }catch(Exception e){ e.printStackTrace(); //事務回滾 sqlSession.rollback(); throw e; }finally{ MyBatisUtil.closeSqlSession(); } } public static void main(String[] args) { StudentDao sd = new StudentDao(); sd.add1(); sd.add2(new Student("64","kaiye","23","男")); } }
