天天看点

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还是注解配置。