1. 程式人生 > >MyBatis入門程式案例

MyBatis入門程式案例

mybatis下載

mybaits的程式碼由github.com管理,地址:https://github.com/mybatis/mybatis-3/releases。 可從該地址下載mybatis最新框架。
下載之後解壓縮:
在這裡插入圖片描述


案例需求

1 根據使用者id查詢y一個使用者資訊
2 根據使用者名稱模糊查詢使用者資訊列表
3 新增使用者資訊
4 修改使用者資訊
5 刪除使用者資訊


MyBatis入門程式配置

1)新建資料庫mybatis

在這裡插入圖片描述

2)新建表user

CREATE TABLE `NewTable` (
`id`  int(4) NOT NULL
AUTO_INCREMENT , `name` varchar(7) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL , PRIMARY KEY (`id`) )ENGINE=InnoDB DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci;

3)新建專案mabatis_demo01(以web專案為例)

在這裡插入圖片描述

4)匯入jar包

工程所需加入的Jar包有mybatis核心包、依賴包和mysql資料驅動包。
在這裡插入圖片描述

5)在工程下新建一個原始碼包config,並在其中建立一個日誌記錄檔案–log4j.properties

在這裡插入圖片描述

log4j.properties檔案:

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

mybatis預設使用log4j作為輸出日誌資訊。

6)在config原始碼包中新建MyBatis的配置檔案SqlMapConfig.xml

在這裡插入圖片描述

SqlMapConfig.xml是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>
    <!-- 和spring整合後environments配置將廢除 -->
    <environments default="development">
        <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/mybatis?characterEncoding=utf-8" />
                <property name="username" value="root" />
                <property name="password" value="123456" />
            </dataSource>
        </environment>
    </environments>
</configuration>

注意:等後面mybatis和Spring兩個框架整合之後,environments的配置將被廢除。

7)建立一個實體類User

在包com.oak.domain下新建實體類User
在這裡插入圖片描述
User類內容為:

public class User {
	//user的id
	private Integer id;
	//user的name
	private String name;
	public User() {
		super();
	}
	public User(Integer id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	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;
	}
	@Override
	public String toString() {
		return "User [id=" + id + ", name=" + name + "]";
	}
}

8)在原始碼包config下新建一個包sqlmap,在其中建立對映檔案user.xml

在該包內新建user.xml,此檔案即sql對映檔案,檔案中配置了操作資料庫的sql語句,此檔案需要在SqlMapConfig.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="test">

</mapper>

namespace:即名稱空間,其用於隔離sql語句(即不同sql對映檔案中的兩個相同id的sql語句如何來區分),這是當前的作用,後面會講另一層非常重要的作用。

9)載入對映檔案。mybatis框架需要載入對映檔案,將user.xml新增在SqlMapConfig.xml中

在SqlMapConfig.xml配置檔案中新增如下配置資訊

<mappers>
    <!-- resource是基於classpath(原始碼包)來查詢的 -->
    <mapper resource="sqlmap/user.xml"/>
</mappers>

在這裡插入圖片描述

10)根據id查詢使用者資訊

在user.xml對映檔案中新增如下配置:

<!-- 根據id獲取使用者資訊 -->
<select id="findUserById" parameterType="int" resultType="com.oak.domain.User">
	select * from `user` where id=#{id};
</select>
  • < select>標籤用於定義查詢語句,相應的還有增刪改

  • parameterType:引數的資料型別,即定義輸入到sql中的對映型別。

  • resultType:結果的資料型別,如果是pojo則應該給出全路徑。

  • #{id}表示使用PreparedStatement設定佔位符號並將輸入變數id傳到sql中。說白點,#{}作用就是佔位符,相當於JDBC中的?。

11)在com.oak.test包中新建MyBatisTest類,在類中新建測試方法:

  @Test
  public void findUserById() throws IOException {
      // 第一步,建立SqlSessionFactoryBuilder物件
      SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
      // 第二步,載入配置檔案
      InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
      // 第三步,建立SqlSessionFactory物件
      SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
      // 第四步,建立SqlSession物件
      SqlSession sqlSession = sqlSessionFactory.openSession();
      // 第五步,使用SqlSession物件執行查詢,得到User物件
      // 第一個引數:執行查詢的StatementId
      User user = sqlSession.selectOne("findUserById", 1);
      // 第六步,列印結果
      System.out.println(user);
      // 第七步,釋放資源,每一個sqlSession就是一個連線
      sqlSession.close();
  }

以上步驟過於繁瑣,而一般來講工廠物件一般在實際開發是單例的,並不需要頻繁地建立,所以我們在此給SqlSessionFactory定義為單例:

public class MyBatisTest {
	// 工廠物件一般在我們的系統中是單例的
	private SqlSessionFactory sqlSessionFactory=null;
	/**
	 * Junit中的基本註解,不是AOP中的那個,
	 * 表示在任意使用@Test註解標註的public void方法執行之前執行
	 * @throws IOException 
	 */
	@Before
	public void init() throws IOException{
		// 第一步,建立SqlSessionFactoryBuilder物件
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        // 第二步,載入配置檔案
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 第三步,建立SqlSessionFactory物件
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
	}
	@Test
    public void findUserById() throws IOException {
        // 第四步,建立SqlSession物件
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 第五步,使用SqlSession物件執行查詢,得到User物件
        // 第一個引數:執行查詢的StatementId
        User user = sqlSession.selectOne("findUserById", 1);
        // 第六步,列印結果
        System.out.println(user);
        // 第七步,釋放資源,每一個sqlSession就是一個連線
        sqlSession.close();
    }
}

執行測試:
在這裡插入圖片描述

12)根據使用者名稱稱模糊查詢使用者資訊列表

在user.xml中新增如下配置:
<!-- 根據名稱模糊查詢使用者資訊列表 -->
<select id="findUserByName" parameterType="String" resultType="com.oak.domain.User">
	select * from `user` where name like #{name}
</select>

如果查詢結果返回的是List集合,那麼resultType只需要設定為List集合中的一個元素的資料型別即可。

在測試類中測試:
@Test 
public void findUserByName(){
	//建立SqlSession物件
	SqlSession sqlSession=sqlSessionFactory.openSession();
	//執行查詢
	List<User> list=sqlSession.selectList("findUserByName","%s%");
	System.out.println(list);
	sqlSession.close();
}

執行測試,檢視結果:
在這裡插入圖片描述

使用${value}字串拼接指令完成此任務

修改xml中的sql為:

<!-- 根據名稱模糊查詢使用者資訊列表 -->
<select id="findUserByName" parameterType="String" resultType="com.oak.domain.User">
	select * from `user` where name like '${value}'
</select>

$ {value}表示使用引數將$ {value}替換,做字串的拼接,${}為字串拼接指令。注意:如果是取簡單資料型別的引數,括號中的值必須為value。
直接執行上述測試方法:
在這裡插入圖片描述
很明顯這種方式在實際開發中是不建議使用的,因為無法防止SQL注入,建議使用#{ }。


小結

1)#{}和${}

#{}:表示一個佔位符號,可以很好地去避免sql注入。其原理是將佔位符位置的整個引數和sql語句兩部分提交給資料庫,資料庫去執行sql語句,去表中匹配所有的記錄是否和整個引數是否一致。
#{}要獲取輸入引數的值:

  • 如果輸入引數是簡單資料型別,則#{}中可以寫value或其它名稱。

  • 如果輸入引數是pojo物件型別,則#{}可通過OGNL方式去獲取,表示式就是屬性.屬性.屬性…方式。

$ {}:表示一個sql拼接符號,其原理是在向資料庫發出sql之前去拼接好sql再提交給數
據庫執行。
${}要獲取輸入引數的值:

  • 如果輸入引數是簡單資料型別,則${}中只能寫value。

  • 如果輸入引數是pojo物件型別,則${}可通過OGNL方式去獲取,表示式就是屬性.屬性.屬性…方式。

一般情況下建議使用#{},特殊情況下必須要用${},比如:

  • 動態拼接sql中動態組成排序欄位,要通過$ {}將排序欄位傳入sql中。

  • 動態拼接sql中動態組成表名,要通過$ {}將表名傳入sql中。

2)parameterType和resultType

parameterType:指定輸入引數型別,mybatis通過ognl方式從輸入物件中獲取引數值拼接在sql中。
resultType:指定輸出結果型別,mybatis將sql查詢結果的一行記錄資料對映為resultType指定型別的物件。

3)selectOne()和selectList()方法

selectOne:查詢一條記錄,如果使用selectOne查詢多條記錄則丟擲異常
selectList:可以查詢一條或多條記錄。


13)新增一條使用者資訊

在xml配置檔案中新增配置:

<!-- 新增一條資訊 -->
<insert id="addUser" parameterType="com.oak.domain.User">
		insert into `user` values(null,#{name})
</insert>

如果輸入引數型別是po,那麼#{}中的名稱就是po類中的屬性,不能隨便定義。
測試類中測試

@Test
public void addUser(){
	//建立SqlSession物件
	SqlSession sqlSession=sqlSessionFactory.openSession();
	sqlSession.insert("addUser", new User(null, "ww"));
	sqlSession.close();
}

檢視控制檯:
在這裡插入圖片描述
檢視資料庫:
在這裡插入圖片描述
雖然發出了sql語句,但是事務並沒將其提交,而是回滾了。故User物件是無法插入到資料庫user表中的。
應該在執行之後進行事務提交。修改測試方法為:

@Test
public void addUser(){
	//建立SqlSession物件
	SqlSession sqlSession=sqlSessionFactory.openSession();
	sqlSession.insert("addUser", new User(null, "ww"));
	sqlSession.commit();
	sqlSession.close();
}

檢視控制檯:
在這裡插入圖片描述
檢視資料庫:
在這裡插入圖片描述
事務已提交,可發現數據庫user表中插入一條記錄。

14)MySQL自增主鍵返回

想要得到MySQL資料庫給我們生成的主鍵id,即獲取主鍵。
這裡要用到MySQL資料庫中的一個函式:

  • LAST_INSERT_ID():返回auto_increment自增列新記錄id值。該函式是在當前事務下取到你最後生成的id值,而我們應知道查詢操作是沒有開啟事務的,增刪改操作是需要開啟事務的。

為了獲取自動主鍵,更改user.xml中的addUser為:

<!-- 新增一條資訊 返回自動增長主鍵 -->
<insert id="addUser" parameterType="com.oak.domain.User">
	<selectKey keyProperty="id" resultType="int" order="AFTER">
        SELECT LAST_INSERT_ID()
    </selectKey>
	insert into `user` values(null,#{name})
</insert>
  • keyProperty:返回的主鍵儲存在po中的哪個屬性(即其對應po的主鍵屬性)。獲取主鍵,實際上是將主鍵取出來之後封裝到了po的主鍵屬性當中。

  • resultType:返回的主鍵是什麼型別(即其對應pojo的主鍵的資料型別)。

  • order:selectKey的執行順序,是相對於insert語句來說的,由於mysql的自增原理,執行完insert語句之後才將主鍵生成,所以這裡selectKey的執行順序為AFTER。

在測試類中修改測試方法為:

@Test
public void addUser(){
	//建立SqlSession物件
	SqlSession sqlSession=sqlSessionFactory.openSession();
	//只給name賦值
	User user=new User(null, "zl");
	sqlSession.insert("addUser", user);
	System.out.println("或者自動增長主鍵:"+user.getId());
	sqlSession.commit();
	sqlSession.close();
}

檢視測試結果:
在這裡插入圖片描述
檢視資料庫:
在這裡插入圖片描述

15)刪除資訊

在user.xml中新增

<!-- 刪除使用者 -->
<delete id="deleteUser" parameterType="int">
	delete from `user` where id=#{id}
</delete>

在測試類中測試:

@Test
public void delUser(){
	//建立SqlSession物件
	SqlSession sqlSession=sqlSessionFactory.openSession();
	sqlSession.delete("deleteUser",1);
	sqlSession.commit();
	sqlSession.close();
}

16)修改資訊

在user.xml中新增修改:

<!-- 修改資訊 -->
<update id="updateUser" parameterType="com.oak.domain.User">
	update `user` set name=#{name} where id=#{id}
</update>

測試:

@Test
public void updateUser(){
	//建立SqlSession物件
	SqlSession sqlSession=sqlSessionFactory.openSession();
	sqlSession.update("updateUser",new User(2, "李四"));
	sqlSession.commit();
	sqlSession.close();
}

MyBatis解決了JDBC程式設計的問題

  • 資料庫連線建立、釋放頻繁造成系統資源浪費從而影響系統性能,如果使用資料庫連線池可解決此問題。
    解決:在SqlMapConfig.xml中配置資料連線池,使用連線池管理資料庫連線。

  • Sql語句寫在程式碼中造成程式碼不易維護,實際應用sql變化的可能較大,sql變動需要改變java程式碼。
    解決:將Sql語句配置在XXXXmapper.xml檔案中與java程式碼分離。

  • 向sql語句傳引數麻煩,因為sql語句的where條件不一定,可能多也可能少,佔位符需要和引數一一對應。
    解決: MyBatis自動將java物件對映至sql語句,通過statement中的parameterType定義輸入引數的型別。

  • 對結果集解析麻煩,sql變化導致解析程式碼變化,且解析前需要遍歷,如果能將資料庫記錄封裝成pojo物件解析比較方便。
    解決: MyBatis自動將sql執行結果對映至java物件,通過statement中的resultType定義輸出結果的型別。