Mybatis入門程式2
阿新 • • 發佈:2019-01-09
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"> <!--namespace 名稱空間,做SQL隔離--> <!--使用者的增刪改查的SQL語句在程式碼中通過id進行呼叫,如果表單特別多,每張表單的SQL語句特別多,id可能重複--> <!--namespace 相當於又加了一層,呼叫的時候通過namespace加上id進行呼叫,避免重名的可能--> <!--namespace起名是有規範的--> <mapper namespace="test"> <!--具有增刪改查對應的子標籤--> <!--id : sql語句唯一標識--> <!--parameterType:指定傳入引數型別,是javaBean中對應屬性的型別--> <!--resultType : 返回結果集型別,如果返回結果為集合,可以呼叫selectList()方法,這個方法返回的結果就是一個集合,所以對映檔案中應該配置成集合泛型的型別--> <select id="findUserById" parameterType="java.lang.Integer" resultType="cn.zst.domain.User"> <!--#{}佔位符,起到佔用的作用,如果傳入的是基本型別(String long double int Boolean float等)那麼 # {}中的變數名稱可以隨意寫--> SELECT * from `user` WHERE id = #{id} </select> <select id ="findUserByName" parameterType="java.lang.String" resultType="cn.zst.domain.User"> <!-- SELECT * from `user` WHERE username like #{name}--> <!--${}拼接符,字串原樣拼接,如果傳入的引數是基本型別(String long double int boolean float等)那麼${}中的變數名稱必須是value--> <!--注意:拼接符有SQL注入的風險,所以慎重使用--> SELECT * from `user` WHERE username like '%${value}%' </select> <!--增加--> <!--如果業務需要返回資料庫自增主鍵,可以使用SELECT LAST_INSERT_ID()--> <insert id="insertUser" parameterType="cn.zst.domain.User"> <!--執行SELECT LAST_INSERT_ID()資料庫函式,返回自增的主鍵--> <!--keyProperty:將返回的主鍵放入傳入引數的id中儲存,此處的傳入引數為User ,--> <!--order:當前函式相對於insert語句的執行順序,在insert前執行是before,在insert後執行是after--> <!--resultType:id 型別 ,也就是在keyproperties中屬性的型別--> <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer"> SELECT LAST_INSERT_ID() </selectKey> <!--如果傳入的是JavaBean型別,那麼#{}中的變數名稱必須是JavaBean中對應的屬性.屬性.屬性.屬性.屬性--> <!--例如,User中有一個Customer的屬性,customer有一個custname屬性,則表示為 customer.custname--> INSERT into `user` (username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address}) </insert> <!--刪除使用者--> <delete id="delUserById" parameterType="java.lang.Integer"> delete from `user` WHERE id=#{id} </delete> <!--更新,根據id來跟新,因為此處傳入的是兩個引數,所有通過user物件傳入,因為它包含所有需要的屬性--> <update id="updateUserById" parameterType="cn.zst.domain.User" > UPDATE `user` set username=#{username} WHERE id=#{id} </update> </mapper>
載入對映檔案
<mappers> <!--url的不用,需要寫在絕對路徑,如 D:/,,,,--> <!--resource 相對路徑 寫完,Ctrl + 左鍵 可以點進去--> <mapper resource="User.xml"/> <!--<mapper resource="UserMapper.xml"/>--> <!--使用class屬性引入介面的全路徑名稱 使用規則: 1 介面的名稱和對映檔名稱除副檔名外要完全相同 2 介面和對映檔案要放在同一個目錄下 --> <mapper class="cn.zst.mapper.UserMapper" /> </mappers>
測試檔案
package cn.zst.test; import cn.zst.domain.User; 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.InputStream; import java.util.Date; import java.util.List; /** * Created by zst on 2019/1/8. */ public class UserTest { @Test public void testFindUserById() throws Exception{ String resource="SqlMapConfig.xml"; //通過流將核心配置檔案讀取出來 InputStream inputStream = Resources.getResourceAsStream(resource); //通過核心配置檔案輸入流來建立會話工廠 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream); //通過工廠建立會話 SqlSession openSession = factory.openSession(); //第一個引數,所呼叫的SQL語句 = namespace+.+sql的id User user = openSession.selectOne("test.findUserById", 1); System.out.println(user); openSession.close(); } @Test public void testFindUserByName() throws Exception{ String resource = "sqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession openSession = factory.openSession(); List<User> list = openSession.selectList("test.findUserByName", "王"); System.out.println(list); openSession.close(); } @Test public void testInsertUser() throws Exception{ String resource = "sqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession openSession = factory.openSession(); User user = new User(); user.setUsername("王名"); user.setBirthday(new Date()); user.setSex("男"); user.setAddress("河南鄭州"); openSession.insert("test.insertUser",user); //提交事務 //如果不提交事務,則資料不能插入到資料庫中 //在Hibernate中如果要提交事務,首先要開啟事務,beganTransation //此處Mybatis會自動開啟事務,但不知道要什麼時候提交事務。所以需要手動提交事務 openSession.commit(); //自增主鍵的id System.out.println(user.getId()); } @Test public void testDelUserById () throws Exception{ String resource = "sqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession openSession = factory.openSession(); openSession.delete("test.delUserById",28); //提交事務 openSession.commit(); } @Test public void testUpdateUserById() throws Exception{ String resource = "sqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession openSession = factory.openSession(); User user = new User(); user.setUsername("王志"); user.setId(24); openSession.update("test.updateUserById",user); openSession.commit(); } }
- #{} 與${}
#{}表示一個佔位符號,通過#{}可以實現preparedStatement向佔位符中設定值,自動進行java型別和jdbc型別轉換,#{}可以有效防止sql注入。 #{}可以接收簡單型別值或JavaBean屬性值。 如果parameterType傳輸單個簡單型別值,#{}括號中可以是value或其它名稱。
${}表示拼接sql串,通過${}可以將parameterType 傳入的內容拼接在sql中且不進行jdbc型別轉換, ${}可以接收簡單型別值或pojo屬性值,如果parameterType傳輸單個簡單型別值,${}括號中只能是value。
- parametertype與resultType
parameterType:指定輸入引數型別,mybatis通過ognl從輸入物件中獲取引數值拼接在sql中。
resultType:指定輸出結果型別,mybatis將sql查詢結果的一行記錄資料對映為resultType指定型別的物件。
- selectOne() 和 selectList()
selectOne查詢一條記錄,如果使用selectOne查詢多條記錄則丟擲異常:
org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:70)
selectList可以查詢一條或多條記錄。
mysql 自增主鍵返回
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
<!-- selectKey將主鍵返回,需要再返回 -->
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select LAST_INSERT_ID()
</selectKey>
insert into user(username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address});
</insert>
新增selectKey實現將主鍵返回
keyProperty:返回的主鍵儲存在pojo中的哪個屬性
order:selectKey的執行順序,是相對與insert語句來說,由於mysql的自增原理執行完insert語句之後才將主鍵生成,所以這裡selectKey的執行順序為after
resultType:返回的主鍵是什麼型別
LAST_INSERT_ID():是mysql的函式,返回auto_increment自增列新記錄id值。
mysql 使用UUID 實現主鍵
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
<selectKey resultType="java.lang.String" order="BEFORE"
keyProperty="id">
select uuid()
</selectKey>
insert into user(id,username,birthday,sex,address)
values(#{id},#{username},#{birthday},#{sex},#{address})
</insert>
<!--注意這裡使用的order是“BEFORE”-->
Mybatis 解決JDBC程式設計的問題
- 資料庫連結建立、釋放頻繁造成系統資源浪費從而影響系統性能,如果使用資料庫連結池可以解決此問題。
解決:在SqlMapConfig.xml中配置資料鏈接池,使用連結池管理資料庫連結。
- Sql語句解除安裝程式碼中造成程式碼不易維護,實際應用sql變化的可能較大,sql變動需要改變java程式碼
解決:將sql語句配置在XXXXmapper.xml檔案與java程式碼分離> 解決:將sql語句配置在XXXXmapper.xml檔案與java程式碼分離
- 向SQL語句傳引數麻煩,因為SQL與語句的where條件不一定,可能多也可能少,佔位符需要和引數一一對應。
解決:Mybatis 自動將java物件對映至SQL語句,通過statement 中的parameterType定義輸入引數的型別
- 對結果集解析麻煩,SQL變化導致解析程式碼變化,且解析前需要遍歷,如果能將資料庫記錄封裝成JavaBean物件解析比較方便
解決:Mybatis自動將sql執行結果對映至java物件,通過statement中resuleType 定義輸出結果的型別。
Mybatis與Hibernate的不同
- Mybatis與Hibernate不同,它不完全是一個ORM框架,需要開發人員自己編寫SQL語句,不過Mybatis可以通過xml或者註解的方式靈活配置要執行的SQL語句,並將java物件和SQL語句對映生成最終執行的SQL,最後將SQL執行的結果再對映生成java物件。
- Mybatis簡單易學,開發人員直接編寫原生態SQL,可嚴格控制SQL執行效能,靈活度高,適合對關係資料模型要求不高的軟體開發,例如網際網路軟體、企業運營類軟體等,因為這類軟體需求變化頻繁,一旦需求變化要求成果輸出迅速。但是靈活的前提是Mybatis無法做到資料庫無關性,如果需要支援多種資料庫的軟體則需要自定義多套sql對映檔案,工作量大。
- Hibernate物件/關係對映能力強,資料庫無關性好,對於關係模型要求高的軟體(如需要固定的定製化軟體)如果用Hibernate開發可以節省很多程式碼,提高效率。