mybatis

一.MyBatis简介

1原理:

Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。

2.MyBatis的框架核心

1、 mybatis配置文件,包括Mybatis全局配置文件和Mybatis映射文件,其中全局配置文件配置了数据源、事务等信息;映射文件配置了SQL执行相关的信息。
2、 mybatis通过读取配置文件信息(全局配置文件和映射文件),构造出SqlSessionFactory,即会话工厂。
3、 通过SqlSessionFactory,可以创建SqlSession即会话。Mybatis是通过SqlSession来操作数据库的。
4、 SqlSession本身不能直接操作数据库,它是通过底层的Executor执行器接口来操作数据库的。Executor接口有两个实现类,一个是普通执行器,一个是缓存执行器(默认)。
5、 Executor执行器要处理的SQL信息是封装到一个底层对象MappedStatement中。该对象包括:SQL语句、输入参数映射信息、输出结果集映射信息。其中输入参数和输出结果的映射类型包括HashMap集合对象、POJO对象类型。

二.Mybatis入门

1.导包

mybatis-3.5.0/lib下所有包
mybatis-3.5.0.jar
mysql-connector-java-5.1.37-bin.jar

2.在classpath下创建log4j.properties
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=/home/miracle/Desktop/mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### set log levels - for more verbose logging change 'info' to 'debug' ###

log4j.rootLogger=debug, stdout
3.编写javaBean

User

package com.miracle.model;

import java.util.Date;

public class User {

    private int id;
    private String username;
    private String sex;
    private Date birthday;
    private String address;

    public User() {

    }

    public User(String username, String sex, Date birthday, String address) {
        this.username = username;
        this.sex = sex;
        this.birthday = birthday;
        this.address = address;
    }

    public int getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", sex='" + sex + '\'' +
                ", birthday=" + birthday +
                ", address='" + address + '\'' +
                '}';
    }
}
4.创建SqlMapConfig.xml(mybatis全局配置文件)



    
    

    
        
        
    

    
    
        
            
            
            
            
                
                
                
                
                
            
        
    

    
    
        
        
        
    

5.编写映射文件User.xml




    
    
    
    

    
    
        
        
            select last_insert_id()
        
        insert into user (username, sex, birthday, address)
        value
        (#{username}, #{sex}, #{birthday}, #{address})
    

    
    
        delete from user where id = #{id}
    

    
    
        update user set address = #{address}, sex = #{sex}
        where id = #{id}
    

6.编写测试类
package com.miracle.test;

import com.miracle.orm.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.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

/**
 * 普通方式
 */
public class Demo {

    private SqlSession sqlSession;

    /**
     * 获取session
     * @throws IOException
     */
    @Before
    public void init() throws IOException {
        // 1.读取配置文件
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        sqlSession = sqlSessionFactory.openSession();
    }

    /**
     * 提交事务
     */
    @After
    public void destory(){
        sqlSession.commit();
        sqlSession.close();
    }
    /**
     * 查询
     */
    @Test
    public void test1(){
                                                 // 这里写xml映射文件的 namespace + id
        User user = (User) sqlSession.selectOne("com.miracle.orm.User.findUserById", 10);
        System.out.println(user);
        List userList = sqlSession.selectList("com.miracle.orm.User.findUserByName", "张");
        System.out.println(userList);
    }

    /**
     * 插入
     */
    @Test
    public void test2(){
        User user = new User("gyf2", "1", new Date(), "广州");
        // 返回受影响的行数
        int affectRow = sqlSession.insert("com.miracle.orm.User.insertUser", user);
        System.out.println(affectRow);
    }

    /**
     * 删除
     */
    @Test
    public void test3(){
        // 返回受影响的行数
        int affectRow = sqlSession.delete("com.miracle.orm.User.deleteUser", 33);
        System.out.println(affectRow);
    }

    /**
     * 更新
     */
    @Test
    public void test4(){
        User user = new User();
        user.setId(27);
        user.setSex("男");
        user.setAddress("深圳");
        // 返回受影响的行数
        int affectRow = sqlSession.update("com.miracle.orm.User.updateUser", user);
        System.out.println(affectRow);
    }

    /**
     * 插入后获取插入数据的id,设置到JavaBean中
     */
    @Test
    public void test5(){
        User user = new User("gyf3", "2", new Date(), "广州");
        // 返回受影响的行数
        int affectRow = sqlSession.insert("com.miracle.orm.User.insertUser", user);
        System.out.println(affectRow);
        // 返回插入数据的id
        int id = user.getId();
        System.out.println(id);
    }
}

三.MyBatis编写Dao层【mapper代理方式实现】

1.概述

Mapper代理的开发方式,程序员只需要编写mapper接口(相当于dao接口)即可。Mybatis会自动的为mapper接口生成动态代理实现类。
不过要实现mapper代理的开发方式,需要遵循一些开发规范。

1. mapper接口的全限定名要和mapper映射文件的namespace的值相同。
2. mapper接口的方法名称要和mapper映射文件中的statement的id相同;
3. mapper接口的方法参数只能有一个,且类型要和mapper映射文件中statement的parameterType的值保持一致。
4. mapper接口的返回值类型要和mapper映射文件中statement的resultType值或resultMap中的type值保持一致;
2.demo

编写mapper接口:UserMapper

package com.miracle.mapper;

import com.miracle.model.User;
import com.miracle.vo.UserQueryVo;
import java.util.List;
import java.util.Map;

public interface UserMapper {
    /*
      有时候去数据库查询一条记录多个列,
      这是没有对应业务的JavaBean对象,
      可以把单条查询结果封装到map中,
      以列名为key,列值为value
     */
    public Map getEmpByIdReturnMap(Integer id);
    
    /**
     * @param user
     * @return  受影响的行数
     */
    // 使用mapper方式开发,那么接口方法的参数只能接收一个参数
    public int save(User user);

    public User findUserById(int id);

    public List findUserByUserQueryVo(UserQueryVo userQueryVo);

    public List findUserListByMap(Map map);

    public int findUserCount(UserQueryVo userQueryVo);

    public User findUserByIdResultMap(int id);

    public List findUserList(UserQueryVo userQueryVo);

    public List findUserByIds(UserQueryVo userQueryVo);

    public List findUserByIds2(List ids);
    /*
       mybatis 增删改 在接口放回方法处
       允许将返回值 void 改为:
       Integer:表示影响行数
       Long:表示影响行数
       Boolean:影响行数超过一,返回true,否则false
    */
    public Long addEmp(Employee employee);

    public Long updateEmp(Employee employee);

    public Boolean deleteEmpById(Integer id);
}

编写xml映射文件:UserMapper.xml






    
    
    
    
        insert into user (username, sex, birthday, address)
        value (#{username}, #{sex}, #{birthday}, #{address})
    

    

    
    

    
    

    
    

    
    
        
        
        
        
        
    
    

    
    
        
            
                sex = #{user.sex}
            
            
                and username like '%${user.username}%'
            
        
    
    
    

    
    

    
    

    
        insert into tbl_employee(last_name, email, gender) values (
            #{lastName},#{email},#{gender}
        )
    

    
        update tbl_employee
        set last_name = #{lastName},
            email = #{email},
            gender = #{gender}
        where id = #{id}
    

    
        delete from tbl_employee where id = #{id}
    

编写测试

package com.miracle.test;

import com.miracle.mapper.UserMapper;
import com.miracle.model.User;
import com.miracle.vo.UserQueryVo;
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.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * mapper代理方式,mapper就相当于dao,用mapper开发就不需要dao了,service层直接调用mapper
 */
@SuppressWarnings("all")
public class Demo {
    private SqlSession sqlSession;
    private UserMapper userMapper;

    /**
     * 获取session
     * @throws IOException
     */
    @Before
    public void init() throws IOException {
        // 1.读取配置文件
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        sqlSession = sqlSessionFactory.openSession();
        // 获取mapper
        userMapper = sqlSession.getMapper(UserMapper.class);
    }

    /**
     * 提交事务
     */
    @After
    public void destory(){
        sqlSession.commit();
        sqlSession.close();
    }

    /**
     * 查询
     */
    @Test
    public void test1(){
        // 查询
        User user = userMapper.findUserById(1);
        System.out.println(user);
    }

    /**
     * 保存
     */
    @Test
    public void test2(){
        // 保存
        User user = new User("王五", "x", new Date(), "xx");
        userMapper.save(user);
    }

    /**
     * 复杂类型查询
     */
    @Test
    public void test3(){
        User user = new User();
        user.setId(1);
        UserQueryVo userQueryVo = new UserQueryVo();
        userQueryVo.setUser(user);
        List userList = userMapper.findUserByUserQueryVo(userQueryVo);
        System.out.println(userList);
    }

    /**
     * map类型查询
     */
    @Test
    public void test4(){
        Map map = new HashMap<>();
        map.put("user", "张");
        map.put("sex", 1);
        List userList = userMapper.findUserListByMap(map);
        System.out.println(userList);
    }

    @Test
    public void test5(){
        UserQueryVo userQueryVo = new UserQueryVo();
        User user = new User();
        user.setSex("2");
        userQueryVo.setUser(user);
        int count = userMapper.findUserCount(userQueryVo);
        System.out.println(count);
    }

    @Test
    public void test6(){
        User user = userMapper.findUserByIdResultMap(1);
        System.out.println(user);
    }

    @Test
    public void test7(){
        User user = new User();
        user.setUsername("张");
        user.setSex("1");
        UserQueryVo userQueryVo = new UserQueryVo();
        userQueryVo.setUser(user);
        List userList = userMapper.findUserList(userQueryVo);
        System.out.println(userList);
    }

    /**
     * foreach 遍历JavaBean中的list
     */
    @Test
    public void test8(){
        List ids = new ArrayList<>();
        ids.add(10);
        ids.add(16);
        ids.add(22);
        ids.add(24);
        UserQueryVo userQueryVo = new UserQueryVo();
        userQueryVo.setIds(ids);
        List userList = userMapper.findUserByIds(userQueryVo);
        System.out.println(userList);
    }

    /**
     * foreach 遍历list
     */
    @Test
    public void test9(){
        List ids = new ArrayList<>();
        ids.add(10);
        ids.add(16);
        ids.add(22);
        ids.add(24);
        List userList = userMapper.findUserByIds2(ids);
        System.out.println(userList);
    }
}

四.mybatis全局配置文件介绍

  • 注意mybatis全局配置文件标签书写是有顺序的

properties

settings

typeAliases

typeHandlers

objectFactory

objectWrapperFactory

plugins

environments?

databaseIdProvider

mappers

1.标签介绍


    
    
        
            
            
            
            
                
                
                
                
                
            
        
    

2.标签介绍

mybatis可以使用properties来引入外部properties配置文件的内容


    
    
	
	
    
        
            
            
            
            
                
                
                
                
                
            
        
    

3.标签介绍


	
	
	    
	    
	    
        
        
        
        
	

4.标签介绍


    
    
        
        
        
        
    

五.mybatisSQL映射文件编写

1.select标签 属性

mybatis_第1张图片

2.mapper 映射文件中 #{} 和 ${} 区别

1.#{} 和 ${} 区别

#{}:相当于预处理中的占位符?。(底层是JDBC的preparedstatement)
	#{}里面的参数表示接收java输入参数的名称。
	#{}可以接受HashMap、POJO类型的参数。
	当接受简单类型的参数时,#{}里面可以是value,也可以是其他。
	#{}可以防止SQL注入。
使用场景:
	尽量用#{}取值



${}:相当于拼接SQL串,对传入的值不做任何解释的原样输出。(底层是JDBC的statement)
	${}会引起SQL注入,所以要谨慎使用。
	${}可以接受HashMap、POJO类型的参数。
	当接受简单类型的参数时,${}里面只能是value。
使用场景:
	比如分表,排序... 按照年份分表拆分:
	select * from ${year}_salary whrere xxx
	select * from tbl_employee order by ${f_name} ${asc}

六.动态SQL

1.If标签

If标签:作为判断入参来使用的,如果符合条件,则把if标签体内的SQL拼接上。
注意:用if进行判断是否为空时,不仅要判断null,也要判断空字符串‘’;

eg:见下图

2.where标签

会去掉条件中的第一个and符号。

eg:见下图

3.choose 分支

4.set 封装修改条件

需求:
想根据JavaBean更新数据库记录,当JavaBean字段非空则更新响应字段,空则不更新


    update tbl_employee
    set
    
        last_name = #{lastName},
    
    
        email = #{email},
    
    
        gender = #{gender}
    
    where id = #{id}

但是这个sql执行会有问题,if标签里面的sql后面有个逗号,无法处理,这是要用到set标签


    update tbl_employee
    
        
            last_name = #{lastName},
        
        
            email = #{email},
        
        
            gender = #{gender}
        
    
    where id = #{id}

5.foreach 遍历

5.trim

    insert into tbl_dept
    
        
            dept_id,
        
        
            dept_name,
        
    
    
        
            #{deptId,jdbcType=INTEGER},
        
        
            #{deptName,jdbcType=VARCHAR},
        
    

五.SQL片断

Mybatis提供了SQL片段的功能,可以提高SQL的可重用性。
mybatis_第2张图片

六.总结

2.selectOne和selectList
selectOne:只能查询0或1条记录,大于1条记录的话,会报错:
selectList:可以查询0或N条记录

3.mybatis特殊字符处理
使用符号进行说明,在最里层的[ ]里面内容不进行解析

4.输出映射 resultType/resultMap
(1)resultType
使用resultType进行结果映射时,查询的列名和映射的pojo属性名完全一致,该列才能映射成功。
如果查询的列名和映射的pojo属性名全部不一致,则不会创建pojo对象;
如果查询的列名和映射的pojo属性名有一个一致,就会创建pojo对象。

输出单个pojo对象和pojo列表时,mapper映射文件中的resultType的类型是一样的,mapper接口的方法返回值不同。同样的mapper映射文件,返回单个对象和对象列表时,mapper接口在生成动态代理的时候,会根据返回值的类型,决定调用selectOne方法还是selectList方法。

(2)resultMap(当mybatis返回JavaBean嵌套JavaBean时,向内层JavaBean里面设置值可以用resultMap)
如果查询出来的列名和属性名不一致,通过定义一个resultMap将列名和pojo属性名之间作一个映射关系。
1、 定义resultMap
2、使用resultMap作为statement的输出映射类型

(3)总结
resultType:将查询结果按照sql列名pojo属性名一致性映射到pojo中。
resultMap:使用association和collection完成一对一和一对多高级映射(对结果有特殊的映射要求)。
association:将关联查询信息映射到一个pojo对象中。
collection:将关联查询信息映射到一个list集合中。

5.mybatis标签大全
https://blog.csdn.net/weixin_40950778/article/details/78655288

你可能感兴趣的:(mybatis)