1. 程式人生 > >Mybatis入門程式2

Mybatis入門程式2

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程式設計的問題

  1. 資料庫連結建立、釋放頻繁造成系統資源浪費從而影響系統性能,如果使用資料庫連結池可以解決此問題。

    解決:在SqlMapConfig.xml中配置資料鏈接池,使用連結池管理資料庫連結。

  2. Sql語句解除安裝程式碼中造成程式碼不易維護,實際應用sql變化的可能較大,sql變動需要改變java程式碼

    解決:將sql語句配置在XXXXmapper.xml檔案與java程式碼分離> 解決:將sql語句配置在XXXXmapper.xml檔案與java程式碼分離

  3. 向SQL語句傳引數麻煩,因為SQL與語句的where條件不一定,可能多也可能少,佔位符需要和引數一一對應。

解決:Mybatis 自動將java物件對映至SQL語句,通過statement 中的parameterType定義輸入引數的型別

  1. 對結果集解析麻煩,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開發可以節省很多程式碼,提高效率。