天天看點

mybatis的注解開發入門

​mybatis注解開發:​

        這幾年來注解開發越來越流行,Mybatis 也可以使用注解開發方式,這樣我們就可以減少編寫 Mapper 映射檔案了。本次我們先圍繞一些基本的 CRUD 來學習,再學習複雜映射關系及延遲加載。

mybatis常用注解說明:

mybatis的注解開發入門

前期準備工作:

使用IDEA軟體制作:

建立Maven工程:

mybatis的注解開發入門

​GroupID​ :是項目組織唯一的辨別符,實際對應JAVA的包的結構,是main目錄裡java的目錄結構。

​ArtifactID​:是項目的唯一的辨別符,實際對應項目的名稱,就是項目根目錄的名稱。

mybatis的注解開發入門

點選下一步,然後點選完成,maven工程就建好了

并且在pom.xml導入對應的坐标

mybatis的注解開發入門

​在resources下建立配置檔案等資訊:​

​編寫SqlMapperConfig.xml:​

<?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">
   <!--上面是限制-->     
<!--mybatis的主配置檔案-->
<configuration>
    <!--導入外部檔案-->
    <properties resource="jdbcConfig.properties"></properties>

    <!--給實體類取别名-->
    <typeAliases>
        <package name="com.itmei.domain"/>
    </typeAliases>

    <!--環境配置-->
    <environments default="mysql">
        <!--mysql環境-->
        <environment id="mysql">
            <!--事務選擇-->
            <transactionManager type="JDBC"></transactionManager>
            <!--資料源-->
            <dataSource type="POOLED">
                <!--資料庫的基本資訊-->
                <property name="driver" value="${jdbc.driver}"/><!--這裡的value要和外置檔案的key一緻-->
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--注冊接口的别名-->
    <mappers>
        <package name="com.itmei.dao"/>
    </mappers>
</configuration>      

​編寫jdbcConfig.properties:資料庫的配置資訊​

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=123456      
mybatis的注解開發入門
mybatis的注解開發入門

​使用 Mybatis 注解實作基本 CRUD:​

完成增删改查等操作:

​建立User實體類​

mybatis的注解開發入門

​注意​:這裡我們故意使實體類的名稱和資料庫列名稱不一樣

​使用注解方式開發持久層接口​

mybatis的注解開發入門

我們先寫2個查詢方法,查詢所有和查詢一個使用者資訊:

其中裡面的注解

    ​@Select​:查詢的語句

    ​@Results​:各個屬性的含義,id為目前結果集聲明唯一辨別,value值為結果集映射關系,@Result代表一個字段的映射關系,column指定資料庫字段的名稱,property指定實體類屬性的名稱,jdbcType資料庫字段類型,@Result裡的id值為true表明主鍵,預設false;使用@ResultMap來引用映射結果集,其中value可省略。

@Results相當于xml裡面的< resultMap >标簽

@ResultMap來引用映射結果集(一般使用在查詢封裝)

mybatis的注解開發入門

​單個參數​

    可以接收基本類型,對象類型,集合類型,都可以接收,mybatis可以直接使用這個參數,不用經過任何處理,同時#{}這裡面的名稱可以随便寫。

注解所有的開發:

package com.itmei.dao;

import com.itmei.domain.User;
import org.apache.ibatis.annotations.*;

import java.util.List;

public interface UserDao {
    /**
     * 查詢所有
     * @return
     */
    @Select("select * from user;")
    @Results(id = "userMap",
            value = {
            @Result(id = true,column = "id",property = "userId"),
            @Result(column = "username",property = "userName"),
            @Result(column = "address",property = "userAddress"),
            @Result(column = "sex",property = "userSex"),
            @Result(column = "birthday",property = "userBirthday"),
    })
    List<User> findAll();

    /**
     * 通過id查詢一個使用者
     * @param id
     * @return
     */
    @Select("select * from user where id=#{uid}") /*這裡單個參數可以随便填寫*/
    @ResultMap("userMap")
    User findById(Integer id);

    /**
     * 儲存使用者
     * @param user
     * @return
     */
    @Insert("insert into user  (username,sex,birthday,address) values (#{userName},#{userSex},#{userBirthday},#{userAddress})")
    @SelectKey(keyColumn = "id",keyProperty = "userId",before = false,resultType = Integer.class,
            statement = {"select last_insert_id()"})/*傳回使用者id的資訊*/
    int saveUser(User user);

    /**
     * 使用者的更新
     * @param user
     * @return
     */
    @Update("update user  set username=#{userName},sex=#{userSex},birthday=#{userBirthday},address=#{userAddress} where id=#{userId}")
    void updateUser(User user);

    /**
     * 删除使用者
     * @param id
     * @return
     */
    @Delete("delete from user where id=#{userId}")
    int deleteUser(Integer id);

    /**
     * 查詢總的資訊(聚合函數)
     * @return
     */
    @Select("select count(*) from user ")
    int findTotal();

    /**
     * 模糊查詢
     * @param name
     * @return
     */
    @Select("select * from user where username like #{userName}")
    @ResultMap("userMap")
    List<User> findByName(String name);


    /*這樣我們就不要編寫UserDao.xml映射檔案*/
}      

​現在我們編寫測試類:​

​UserTest測試類:​

public class UserTest {
    private InputStream in;
    private  SqlSession session;
    private UserDao userDao;

    @Before/*在測試執行之前運作*/
    public void init() throws Exception{
        //1.讀取配置檔案
         in= Resources.getResourceAsStream("SqlMapperConfig.xml");
        //2.建立工廠對象
        SqlSessionFactory factory= new SqlSessionFactoryBuilder().build(in);
        //3.建立SqlSession對象 并且更改為自動添加事務
         session = factory.openSession(true);
        //4.通過session對象建立dao的代理對象
         userDao = session.getMapper(UserDao.class);
    }
    @After/*在測試執行之後運作*/
    public void end() throws Exception{
        //6.釋放資源
        session.close();
        in.close();
    }
 }      
mybatis的注解開發入門

所有的測試方法和代碼:

package com.itmei.Test;

import com.itmei.dao.UserDao;
import com.itmei.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.After;
import org.junit.Before;
import org.junit.Test;

import java.io.InputStream;
import java.util.Date;
import java.util.List;

public class UserTest {
    private InputStream in;
    private  SqlSession session;
    private UserDao userDao;

    @Before/*在測試執行之前運作*/
    public void init() throws Exception{
        //1.讀取配置檔案
         in= Resources.getResourceAsStream("SqlMapperConfig.xml");
        //2.建立工廠對象
        SqlSessionFactory factory= new SqlSessionFactoryBuilder().build(in);
        //3.建立SqlSession對象 并且更改為自動添加事務
         session = factory.openSession(true);
        //4.通過session對象建立dao的代理對象
         userDao = session.getMapper(UserDao.class);
    }
    @After/*在測試執行之後運作*/
    public void end() throws Exception{
        //6.釋放資源
        session.close();
        in.close();
    }

    /**
     * 查詢所有使用者
     */
    @Test
    public void testFindAll(){
        List<User> users = userDao.findAll();
        for (User user:users){
            System.out.println(user);
        }
    }

    /**
     * 查詢一個使用者
     */
    @Test
    public void testFindById(){
        User user = userDao.findById(41);
        System.out.println(user);
        //結果:User{userId=41, userName='update user clear cache', userAddress='北京朝陽區', userSex='男', userBirthday=Tue Feb 27 17:47:08 CST 2018}
    }

    /**
     * 儲存使用者
     */
    @Test
    public void testSaveUser(){
        User user=new User();
        user.setUserName("MJW");
        user.setUserSex("男");
        user.setUserAddress("北京");
        user.setUserBirthday(new Date());
        System.out.println("使用者資訊"+user);
        //結果:使用者資訊User{userId=null, userName='MJW', userAddress='北京', userSex='男', userBirthday=Sun Jun 07 15:41:48 CST 2020}
         userDao.saveUser(user);
        System.out.println("使用者資訊"+user);
        //結果:使用者資訊User{userId=69, userName='MJW', userAddress='北京', userSex='男', userBirthday=Sun Jun 07 15:41:48 CST 2020}

    }

    /**
     * 更新使用者,通過id
     */
    @Test
    public void testupdateUser(){
        User user=new User();
        user.setUserId(69);
        user.setUserName("update");
        user.setUserSex("男");
        user.setUserAddress("北京");
        user.setUserBirthday(new Date());
        userDao.updateUser(user);
        //調用方法查詢使用者
        User u = userDao.findById(69);
        System.out.println(u);
        //結果:User{userId=69, userName='update', userAddress='北京', userSex='男', userBirthday=Sun Jun 07 15:48:14 CST 2020}
    }


    /**
     * 删除一個使用者
     */
    @Test
    public void testdelete(){
         userDao.deleteUser(68);
    }


    /**
     * 查詢總記錄數
     */
    @Test
    public void testFindTotal(){
        int total = userDao.findTotal();
        System.out.println("總記錄數:"+total);
        //總記錄數:17
    }


    /**
     * 模糊查詢
     */
    @Test
    public void testFindByName(){
        String name="%王%";
        List<User> users = userDao.findByName(name);
        for (User user:users){
            System.out.println(user);
        }
        /*User{userId=42, userName='小二王', userAddress='北京金燕龍', userSex='女', userBirthday=Fri Mar 02 15:09:37 CST 2018}
        User{userId=43, userName='小二王', userAddress='北京金燕龍', userSex='女', userBirthday=Sun Mar 04 11:34:34 CST 2018}
        User{userId=46, userName='老王', userAddress='北京', userSex='男', userBirthday=Wed Mar 07 17:37:26 CST 2018}*/
    }


}      

使用注解實作複雜關系映射開發

        實作複雜關系映射之前我們可以在映射檔案中通過配置< resultMap>來實作,在使用注解開發時我們需要借助@Results 注解,@Result 注解,@One 注解,@Many 注解。

​複雜關系映射的注解說明​

mybatis的注解開發入門

使用注解實作 (一對一) 複雜關系映射及延遲加載

  需求:

         加載賬戶資訊時并且加載該賬戶的使用者資訊,根據情況可實作延遲加載。(注解方式實作)

​添加 User 實體類及 Account 實體類​

User 實體類

package com.itheima.domain;

import java.io.Serializable;
import java.util.Date;

/**
 * @author 黑馬程式員
 * @Company http://www.ithiema.com
 */
public class User implements Serializable{

    private Integer userId;
    private String userName;
    private String userAddress;
    private String userSex;
    private Date userBirthday;
    
    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserAddress() {
        return userAddress;
    }

    public void setUserAddress(String userAddress) {
        this.userAddress = userAddress;
    }

    public String getUserSex() {
        return userSex;
    }

    public void setUserSex(String userSex) {
        this.userSex = userSex;
    }

    public Date getUserBirthday() {
        return userBirthday;
    }

    public void setUserBirthday(Date userBirthday) {
        this.userBirthday = userBirthday;
    }

    @Override
    public String toString() {
        return "User{" +
                "userId=" + userId +
                ", userName='" + userName + '\'' +
                ", userAddress='" + userAddress + '\'' +
                ", userSex='" + userSex + '\'' +
                ", userBirthday=" + userBirthday +
                '}';
    }
}      

​Account 實體類​ :實體類屬性名稱和資料庫列一緻

package com.itheima.domain;

import java.io.Serializable;

/**
 * @author 黑馬程式員
 * @Company http://www.ithiema.com
 */
public class Account implements Serializable {

    private Integer id;
    private Integer uid;
    private Double money;

    //多對一(mybatis中稱之為一對一)的映射:一個賬戶隻能屬于一個使用者
    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getUid() {
        return uid;
    }

    public void setUid(Integer uid) {
        this.uid = uid;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", uid=" + uid +
                ", money=" + money +
                '}';
    }
}      

添加User對象引用

mybatis的注解開發入門

​添加Account賬戶的持久層接口并使用注解配置​

mybatis的注解開發入門

​@One​:相當于< association>的配置(一對一)

​select屬性​:代表要執行的sql語句(這裡全限定類名加方法名稱這樣他就可以知道對應sql語句)

​fetchType屬性​:代表加載方式,一般如果要延遲加載都設定為 LAZY 的值

​添加UserDao使用者的持久層接口并使用注解配置​

mybatis的注解開發入門

​測試一對一關聯及延遲加載​

AccountTset測試類:

package com.itmei.Test;

import com.itmei.dao.AccountDao;
import com.itmei.dao.UserDao;
import com.itmei.domain.Account;
import com.itmei.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.After;
import org.junit.Before;
import org.junit.Test;

import java.io.InputStream;
import java.util.Date;
import java.util.List;

public class AccountTest {
    private InputStream in;
    private  SqlSession session;
    private AccountDao accountDao;

    @Before/*在測試執行之前運作*/
    public void init() throws Exception{
        //1.讀取配置檔案
         in= Resources.getResourceAsStream("SqlMapperConfig.xml");
        //2.建立工廠對象
        SqlSessionFactory factory= new SqlSessionFactoryBuilder().build(in);
        //3.建立SqlSession對象 并且更改為自動添加事務
         session = factory.openSession(true);
        //4.通過session對象建立dao的代理對象
        accountDao = session.getMapper(AccountDao.class);
    }
    @After/*在測試執行之後運作*/
    public void end() throws Exception{
        //6.釋放資源
        session.close();
        in.close();
    }

    /**
     * 查詢所有使用者
     */
    @Test
    public void testFindAll(){
        List<Account> accounts = accountDao.findAll();
       /* for (Account account:accounts){
            System.out.println(account);
        }*/
    }




}      

運作後發現什麼都沒有顯示,原因是我沒有輸出,我如果把for循環不注釋,你就看不出延遲加載的差別,我們現在在pom.xml裡面多寫一個坐标,并且建立一個log4j.properties的資料資訊,我會把代碼放進去。

mybatis的注解開發入門
mybatis的注解開發入門

添加完成後,在運作可以看出代碼的日志資訊,我們隻通路了account的表。

mybatis的注解開發入門

           按正常道理當調用了findAll方法就會執行注解的所有資料,但是通過fetchType=FetchType.LAZY 實作延遲加載(按需加載),在進行表的關聯查詢時,按照設定延遲規則推遲對關聯對象的select查詢。例如在進行一對多查詢的時候,隻查詢出一方,當程式中需要多方的資料時,mybatis再發出sql語句進行查詢,這樣子延遲加載就可以的減少資料庫壓力。

我們for循環周遊需要查詢user表和account表時我們可以看出,查詢了user和account表

mybatis的注解開發入門

FetchType 有三個參數分别是延遲加載,預設加載,立即加載

mybatis的注解開發入門

log4j.properties的代碼:

建立一個log4j.properties把下面代碼直接複制到裡面

# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE            debug   info   warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE

# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE

# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n      
mybatis的注解開發入門

使用注解實作 (多對一) 複雜關系映射

需求:

         查詢使用者資訊時,也要查詢他的賬戶清單。使用注解方式實作。

分析:

         一個使用者具有多個賬戶資訊,是以形成了使用者(User)與賬戶(Account)之間的一對多關系。

​3.3.3.1 User 實體類加入 List< Account>​

mybatis的注解開發入門

​3.3.3.2 編寫UserDao使用者的持久層接口并使用注解配置​

mybatis的注解開發入門

​3.3.3.3 編寫AccountDao賬戶的持久層接口并使用注解配置​

mybatis的注解開發入門

​UserTest添加測試方法​

package com.itmei.Test;

import com.itmei.dao.AccountDao;
import com.itmei.dao.UserDao;
import com.itmei.domain.Account;
import com.itmei.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.After;
import org.junit.Before;
import org.junit.Test;

import java.io.InputStream;
import java.util.List;

public class UserTest {
    private InputStream in;
    private  SqlSession session;
    private UserDao userDao;

    @Before/*在測試執行之前運作*/
    public void init() throws Exception{
        //1.讀取配置檔案
         in= Resources.getResourceAsStream("SqlMapperConfig.xml");
        //2.建立工廠對象
        SqlSessionFactory factory= new SqlSessionFactoryBuilder().build(in);
        //3.建立SqlSession對象 并且更改為自動添加事務
         session = factory.openSession(true);
        //4.通過session對象建立dao的代理對象
        userDao = session.getMapper(UserDao.class);
    }
    @After/*在測試執行之後運作*/
    public void end() throws Exception{
        //6.釋放資源
        session.close();
        in.close();
    }

    /**
     * 查詢所有使用者
     */
    @Test
    public void testFindAll(){
        List<User> users = userDao.findAll();
      /*  for (User user:users){
            System.out.println("----每個賬戶的資訊-----");
            System.out.println(user);
        }*/
    }




}      

       運作結果:因為使用延遲加載,是以我們沒有調用裡面的方法他隻會查詢user表,使for循環那麼會調用方法查詢使用者的資訊,簡稱按需加載。

mybatis的注解開發入門

調用方法查詢user表和account表(按需加載)

mybatis的注解開發入門

mybatis 基于注解的二級緩存

​在 SqlMapConfig 中開啟二級緩存支援​

mybatis的注解開發入門
mybatis的注解開發入門

​在持久層接口中使用注解配置二級緩存​

在要配置二級緩存的持久層接口上配置

mybatis的注解開發入門
mybatis的注解開發入門

總結:

​mybatis的入門​

    ​mybatis的環境搭建​

             第一步:建立maven工程并導入坐标

             第二步:建立實體類和dao的接口

             第三步:建立Mybatis的主配置檔案

                           SqlMapConifg.xml

             第四步:建立映射配置檔案

                            IUserDao.xml

     ​環境搭建的注意事項:​

             第一個:建立IUserDao.xml 和 IUserDao.java時名稱是為了和我們之前的知識保持一緻。

                         在Mybatis中它把持久層的操作接口名稱和映射檔案也叫做:Mapper

                  是以:IUserDao 和 IUserMapper是一樣的

           第二個:在idea中建立目錄的時候,它和包是不一樣的

               包在建立時:com.itheima.dao它是三級結構

               目錄在建立時:com.itheima.dao是一級目錄

           第三個:mybatis的映射配置檔案位置必須和dao接口的包結構相同

           第四個:映射配置檔案的mapper标簽namespace屬性的取值必須是dao接口的全限定類名

           第五個:映射配置檔案的操作配置(select),id屬性的取值必須是dao接口的方法名

             當我們遵從了第三,四,五點之後,我們在開發中就無須再寫dao的實作類。

          ​mybatis的入門案例​

                 第一步:讀取配置檔案

                 第二步:建立SqlSessionFactory工廠

                 第三步:建立SqlSession

                 第四步:建立Dao接口的代理對象

                 第五步:執行dao中的方法

                 第六步:釋放資源

            ​注意事項:​

                 不要忘記在映射配置中告知mybatis要封裝到哪個實體類中

                 配置的方式:指定實體類的全限定類名

          ​基于注解的入門案例:​

                 把IUserDao.xml移除,在dao接口的方法上使用@Select注解,并且指定SQL語句

                 同時需要在SqlMapConfig.xml中的mapper配置時,使用class屬性指定dao接口的全限定類名。

           ​明确:​

                 我們在實際開發中,都是越簡便越好,是以都是采用不寫dao實作類的方式。

                 不管使用XML還是注解配置。