Mybatis学习笔记

目录

  • 1、简介
      • 什么是MyBatis?
          • 持久层
          • 持久层
      • 为啥要用Mybatis?
  • 2、第一个Mybatis程序
          • 1、在pom.xml添加依赖
          • 2、创建实体类
          • 3、编写映射文件Mapper
          • 4、编写核心配置文件
          • 5、测试代码
  • 3、CRUD
      • Insert
          • 1、编写Mapper.xml文件
          • 2、继续测试
          • 注意事项
      • update
          • 1、编写Mapper.xml
          • 2、测试插入操作
          • 注意事项
      • delete
          • 1、编写Mapper.xml
          • 2、测试代码
          • 注意事项
  • 4、IDEA自定义模板
  • 5、生命周期和作用域
          • 1、SqlSessionFactoryBuilder对象
          • 2、SqlSessionFactory对象
          • 3、SqlSession:
  • 6、Mybatis的Dao层实现
      • 传统方式
          • 2、UserMapper接口
          • 3、实现Mapper接口
          • 4、编写Mapper文件
          • 5、编写核心配置文件
          • 6、测试
      • ==使用代理方式==
          • 测试
  • 7、动态SQL
      • if 标签
      • where 标签
      • foreach 标签
      • SQL片段抽取
  • 8、解决属性名和字段名不一致问题
          • 使用resultMap
  • 9、开启日志
          • STDOUT_LOGGING
          • LOG4J
          • 1、添加依赖
          • 2、在resources目录下创建log4j.properties文件,写入一下内容
          • 3、 配置log4j为日志的实现
          • Log4j的简单使用
          • 2、获取日志对象,参数为当前类的class
  • 10、使用注解开发
      • 面向接口编程
          • 关于接口的理解
          • 三个面向区别
      • 使用注解开发
          • 1 注解在接口方法上实现
          • 2 核心配置文件中绑定接口
  • 11、参数
      • ==多个参数 使用@Param方式==
      • ==多个参数 使用对象方式传==
      • 多个参数 按位置
      • 多个参数 使用map
      • # 和 $
  • 12、封装MyBatis的输出结果
      • 使用resultType
          • 简单类型
          • 自定义类型的别名
          • 返回Map
      • resultMap
      • 属性名和列名不同的处理方式
        • 模糊查询 like
  • 13、Mybatis核心配置文件
      • environments (环境配置)
          • 其中实物管理的类型有两种
          • 其中数据源的类型有三种
      • properties(属性)
          • 如果外部配置文件和内部配置中有相同字段,优先使用外部的!
      • typeAliases(类型别名)
      • settings(设置)
      • mappers(映射器)
          • 方式一:使用resource绑定注册
          • 方式二:使用class文件绑定注册
          • 方式三:使用扫描包绑定注册
          • 方式四:使用URL绑定注册
  • 14、多表操作
      • 一对一
      • 一对多
  • 15、缓存
          • 什么是缓存?
          • 为什么使用缓存?
          • 什么样的数据能使用缓存?
      • 一级缓存
          • 缓存失效的情况
      • 二级缓存

1、简介

什么是MyBatis?

  • MyBatis是一款优秀的持久层框架
  • 它支持定制化SQL、存储过程以及高级映射。
  • MyBatis避免了几乎所有的JDBCI代码和手动设置参数以及获取结果集。
  • MyBatis 可以使用简单的XML或注解来配置和映射原生类型、接口和Java的POJO(Plain old JavaObjects,普通老式Java对象)为数据库中的记录。

MyBatis本是 apache的一个开源项目 iBatis, 2010年这个项目由 apache software foundation迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github

持久层

数据持久化:jdbc、数据库、io文件保存等

持久层

Dao层、Servci层、Controller层

  • 完成持久化工作的代码块
  • 层与层之间界限明显

为啥要用Mybatis?

  • 帮程序将数据存入数据库中

  • 方便

  • 传统的JDBC代码太复杂了。简化。框架。自动化。

2、第一个Mybatis程序

步骤:

  • 添加MyBatis的坐标
  • 创建user数据表
  • 编写User实体类
  • 编写映射文件UserMapper.xml
  • 编写核心配置文件SqIMapConfig.xml
  • 测试代码
1、在pom.xml添加依赖

<dependency>
    <groupId>org.mybatisgroupId>
    <artifactId>mybatisartifactId>
    <version>3.5.1version>
dependency>

<dependency>
    <groupId>mysqlgroupId>
    <artifactId>mysql-connector-javaartifactId>
    <version>5.1.9version>
dependency>
2、创建实体类
public class User {
    private String phone;
    private String password;
    private int id;
    @Override
    public String toString() {
        return "User{" +
                "phone='" + phone + '\'' +
                ", password='" + password + '\'' +
                ", id=" + id +
                '}';
    }
    public String getPhone() {
        return phone;
    }
    public void setPhone(String phone) {
        this.phone = phone;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
}
3、编写映射文件Mapper


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="userMapper">
    
    <select id="findall" resultType="com.wei.domain.User">
	    select * from users;
	  select>
mapper>
4、编写核心配置文件

DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/数据库名?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
                <property name="username" value="用户名"/>
                <property name="password" value="密码"/>
            dataSource>
        environment>
    environments>
    
    <mappers>
        
        <mapper resource="com/wei/domain/UserMapper.xml"/>
    mappers>

configuration>
5、测试代码
 
public class MyTest01 {
    @Test
    public void test01() throws IOException {
        String config = "sqlMapConfig.xml";
        //获得核心配置文件
        InputStream is = Resources.getResourceAsStream(config);
        //获得工厂对象
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);
        // 获得session会话对象,这个就是数据库对象了
        SqlSession sqlSession = build.openSession();
        //执行操作
        //selectList 参数:mapper文件中的namespace + id
        List<User> userList = sqlSession.selectList("userMapper.findall");
        //打印数据
        for(User item : userList){
            System.out.println(item);
        }
        sqlSession.close();
    }
}

输出结果:

User{id=1, phone=‘120’, password=‘123456’}
User{id=2, phone=‘987654321’, password=‘123456’}
User{id=3, phone=‘110’, password=‘123456’}

  • 注意:IDEA默认不扫描 .properties.xml 文件,所以必须要在pom.xml文件的标签中加入一下这一行
<resources>
    <resource>
        <directory>src/main/javadirectory>	
        <includes>
            <include>**/*.propertiesinclude>
        	<include>**/*.xmlinclude>
        includes>
        <filtering>falsefiltering>
    resource>
resources>

3、CRUD

Insert

向数据库表中插入数据

标签属性:

  • id
  • parameType:参数的类型
1、编写Mapper.xml文件


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="userMapper">
    
    <select id="findall" resultType="com.wei.domain.User">
	    select * from users;
    select>
    
    <insert id="insertOne" parameterType="com.wei.domain.User">
        insert into users value(#{id},#{phone},#{password})
    insert>
mapper>
2、继续测试
 @Test
    public void test02() throws IOException {
        //创建User对象,用来插入数据库
        User user = new User();
        user.setId(4);
        user.setPhone("147258369");
        user.setPassword("123456");
        
        String config = "sqlMapConfig.xml";
        //获得核心配置文件
        InputStream is = Resources.getResourceAsStream(config);
        //获得工厂对象
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);
        // 获得session会话对象,这个就是数据库对象了
        SqlSession sqlSession = build.openSession();
        
        //执行插入操作,参数:第一个还是namespace + id,第二个是要插入的对象
        sqlSession.insert("userMapper.insertOne",user);
        sqlSession.commit();
        
        sqlSession.close();
    }

这时需要我们手动提交事务,因为Mybatis默认不自动提交事务。

为什么sqlSession中有事务提交?因为它就是个数据库对象啊。

刷新数据库,可以看到新的数据被插入
Mybatis学习笔记_第1张图片

注意事项
  • 插入语句使用 insert 标签
  • 在映射文件中使用 parameterType 属性指定要插入的数据类型
  • Sql语句中使用 #{实体类属性名称} 方式引用实体中的属性值
  • 插入操作使用的API是 sqlsesion.insert(“命名空间.id”,实体对象);
  • 插入、更新、删除操作都涉及到数据库中数据变化,所以要手动提交事务,即sqlSession.commit()

update

修改数据库中数据

1、编写Mapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="userMapper">
    
    <select id="findall" resultType="com.wei.domain.User">
	    select * from users;
    select>
    
    <insert id="insertOne" parameterType="com.wei.domain.User">
        insert into users value(#{id},#{phone},#{password})
    insert>
    
    <update id="update" parameterType="com.wei.domain.User">
        update users set phone=#{phone},password=#{password} where id=#{id}
    update>
mapper>
2、测试插入操作
@Test
    public void test03() throws IOException {
        //创建User对象,修改id为4的数据
        User user = new User();
        user.setId(4);
        user.setPhone("123456789");
        user.setPassword("654321");

        String config = "sqlMapConfig.xml";
        //获得核心配置文件
        InputStream is = Resources.getResourceAsStream(config);
        //获得工厂对象
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);
        // 获得session会话对象,这个就是数据库对象了
        SqlSession sqlSession = build.openSession();
        //修改id为4的数据
        sqlSession.update("userMapper.update",user);
        sqlSession.commit();

        sqlSession.close();
    }

Mybatis学习笔记_第2张图片

注意事项
  • 修改语句使用update标签
  • 修改操作使用的API是sqlSession.update(“命名空间.id”,实体对象);

delete

删除数据库中的数据

1、编写Mapper.xml


DOCTYPE mapper
       PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
       "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="userMapper">
   
   <select id="findall" resultType="com.wei.domain.User">
       select * from users;
   select>
   
   <insert id="insertOne" parameterType="com.wei.domain.User">
       insert into users value(#{id},#{phone},#{password})
   insert>
   
   <update id="update" parameterType="com.wei.domain.User">
       update users set phone=#{phone},password=#{password} where id=#{id}
   update>

   <delete id="deleteById" parameterType="int">
       delete from users where id = #{id}
   delete>
mapper>

这里的删除操作是根据id来删除表中的数据段,只有一个参数,#{}中的名字随便起,由于id在数据库是int,所以这里参数类型是int

2、测试代码
 @Test
    public void test04() throws IOException {

        String config = "sqlMapConfig.xml";
        //获得核心配置文件
        InputStream is = Resources.getResourceAsStream(config);
        //获得工厂对象
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);
        // 获得session会话对象,这个就是数据库对象了
        SqlSession sqlSession = build.openSession();

        //第二个参数:删除id为4的一行数据
        sqlSession.update("userMapper.deleteById",4);
        sqlSession.commit();

        sqlSession.close();
    }
注意事项
  • 删除语句使用delete标签
  • Sql语句中使用#{任意字符串}方式引用传递的单个参数
  • 删除操作使用的API是sqlSession.delete(“命名空间.id”,Object);

4、IDEA自定义模板

Mybatis学习笔记_第3张图片

5、生命周期和作用域

生命周期,和作用域,是至关重要的,因为错误的使用会导致非常严重的并发问题

1、SqlSessionFactoryBuilder对象
  • 主要用来生产SqlSessionFactory,之后就用不到了
  • 放在局部变量
2、SqlSessionFactory对象
  • 可以看成数据库连接池

  • SqlSessionFactory一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例

  • 因此 SqlSessionFactory的最佳作用域是应用作用域

  • 一般都放在静态代码块中

3、SqlSession:
  • 获取连接池中连接的请求
  • 用完之后立即关闭
  • 不是线程安全的,不能被共享,最佳作用域是请求或者方法的作用域

6、Mybatis的Dao层实现

传统方式

步骤:

  • 编写实体类

  • 编写UserMapper接口

  • 写实现类去实现Mapper接口

  • 编写Mapper文件

  • 编写核心配置文件

  • 测试

1、实体类

package com.wei.domain;

public class User {
    private int id;
    private String phone;
    private String password;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", phone='" + phone + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    public int getId() {
        return id;
    }

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

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
2、UserMapper接口
package com.wei.dao;
import com.wei.domain.User;
import java.io.IOException;
import java.util.List;

public interface UserMapper {
    // 查找所有用户信息
    public List<User> findAll() throws IOException;
}
3、实现Mapper接口
package com.wei.dao.impl;
import com.wei.dao.UserMapper;
import com.wei.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 java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class UserMapperImpl  implements UserMapper {
    @Override
    public List<User> findAll() throws IOException {
        InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);

        SqlSession sqlSession = build.openSession();

        List<User> list = sqlSession.selectList("userMapper.findAll");
        return list;
    }
}
4、编写Mapper文件


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="userMapper">
    <select id="findAll" resultType="com.wei.domain.User">
	    select * from users;
    select>
mapper>
5、编写核心配置文件

DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    
    <properties resource="jdbc.properties">properties>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver"   value="${jdbc.driver}"/>
                <property name="url"      value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            dataSource>
        environment>
    environments>

    <mappers>
        <mapper resource="com/wei/mapper/UserMapper.xml"/>
    mappers>

configuration>
6、测试
 @Test
public void test01() throws IOException {
    UserMapper user = new UserMapperImpl();
    List<User> all = user.findAll();
    for(User item : all){
        System.out.println(item);
    }
}

输出结果:

User{id=1, phone=‘120’, password=‘123456’}
User{id=2, phone=‘987654321’, password=‘123456’}
User{id=3, phone=‘110’, password=‘123456’}

缺点:

总是要是对象的接口实现,太麻烦了

使用代理方式

采用Mybatis的代理开发方式实现DAO层的开发,这种方式是进入企业的主流。
Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。

Mapper接口开发需要遵循以下规范:

  • 1、Mapper.xml文件中的namespace与mapper接口的全限定名相同
  • 2、Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
  • 3、Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
  • 4、Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
测试
@Test
public void test01() throws IOException {
    InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
    SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);
    SqlSession sqlSession = build.openSession();
    //使用代理
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    //直接调用方法
    List<User> all = mapper.findAll();
    for(User item : all){
        System.out.println(item);
    }
	sqlSession.close();
}

7、动态SQL

sql语句是动态变化的,可以根据条件获取不同的slq语句

主要是where的部分发生变化

动态sql的实现使用的是mybatis提供的标签

if 标签

对于该标签的执行,当test的值为true时,会将其包含的SQL片断拼接到其所在的SQL语句中。

语法:

​ sql语句的部分


<mapper namespace="com.wei.dao.UserMapper">
    <select id="findByCondition" 
    			parameterType="com.wei.domain.User" 
            	resultType="com.wei.domain.User">
        select * from users where 1=1
        <if test="id!=0">
            and id = #{id}
        if>
        <if test="phone!=null">
            and phone = #{phone}
        if>
    select>
mapper>

id和phone不传入情况下为了防止出错,设置where 1=1

where 标签

用来包含多个的,当多个if中有一个成立的,会自动增加一个where关键字,并去掉 if 中多余的and , or

<select id="findByCondition02" resultType="com.wei.domain.User">
    select * from student
    <where>
        <if test="id!=0">
            and id = #{id}
        if>
        <if test="phone!=null">
            and phone = #{phone}
        if>
    where>
select>

foreach 标签

用来循环java中的数组,list集合的。主要用在sql的in语句中。


属性:

  • collection:表示接口中的方法参数的类型,如果是数组使用array,如果是list集合使用list
  • item:自定义的,表示数组和集合成员的变量(随便起名)
  • open:循环开始是的字符
  • close:循环结束时的字符
  • separator:集合成员之间的分隔符

java代码

sqlsession sqlsession = MyBatisutils.getsqlsession();
UserMapper mapper = sqlsession.getMapper(UserMapper.class);

List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
List<User> users = mapper.findByIds(list);

for(User item: users){
	system.out.println(item);
}

mapper文件

<select id="findByIds" parameteType="list" 
                      resultType="com.wei.domain.User">
    select * from users
    <where>
        
        <foreach collection="list" item="myid" open="id in (" close=")" separator=",">
            #{myid}
        foreach>
        
    where>
                                                                           
select>

mysql预编译后结果:Preparing: select * from users where id in ( ?, ? )

SQL片段抽取

标签 用于定义sql 片断,以便其它SQL标签复用。而其它标签使用该SQL片断,需要使用
子标签。该标签可以定义sQL语句中的任何部分,所以子标签可以放在动态sQL的任何位置。

步骤:

  • 1):先定义 sql语句 / 表名 / 字段等
  • 2):使用 引用
<sql id="stusql"> select * from student /sql>	

<select id="..." resultType="...">
	<include refid="stusql"/> 
select>

8、解决属性名和字段名不一致问题

使用resultMap

结果集映射

数据库中名字:id name pwd
实体类中 : id name password

例如:


<resultMap id="UserMap" type="User">
    
    <result column="id" property="id" />
    <result column="name" property="name" />
    <result column="pwd" property="password" />
resultMap>
                                   	
<select id="getUserById" resultMap="UserMap">
	select * from user where id = #{id}
select>

9、开启日志

STDOUT_LOGGING

如果一个数据库操作,出现了异常,我们需要排错。日志就是最好的助手!

SLF4J
LOG4J【掌握】
LOG4j2
JDK_LOGGING
COMMONS_LOGGING
STDOUT_LOGGING【掌握】
NO_LOGGING

在Mybatis核心配置文件中添加下面三行即可开启日志

<settings>    <setting name="logImpl" value="STDOUT_LOGGING"/>settings>
LOG4J
1、添加依赖
2、在resources目录下创建log4j.properties文件,写入一下内容
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file

#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/wei.log			//将日志输出到当前文件下log/wei.log文件中
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n

#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
3、 配置log4j为日志的实现
Log4j的简单使用
  • 1、再要使用log4j中的类中,导入包

  • 2、获取日志对象,参数为当前类的class
    • static Logger logger = Logger.getLogger(UserDaoTest.class);
      
  • 3、使用info、debug、error方法

      logger.info("info:进入了方法");
      logger.debug("debug:进入了方法");
      logger.error("error:进入了方法");
    

10、使用注解开发

面向接口编程

大家之前都学过面向对象编程,也学习过接口,但在真正的开发中,很多时候我们会选择面向接口编程
根本原因︰解耦,可拓展,提高复用,分层开发中,上层不用管具体的实现,大家都遵守共同的标准,使得开发变得容易,规范性更好
在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了;
而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程。

关于接口的理解

-接口从更深层次的理解,应是定义(规范,约束)与实现(名实分离的原则)的分离。-接口的本身反映了系统设计人员对系统的抽象理解。
-接口应有两类:
-第一类是对一个个体的抽象,它可对应为一个抽象体(abstract class);-第二类是对一个个体某一方面的抽象,即形成一个抽象面(interface) ;-一个体有可能有多个抽象面。抽象体与抽象面是有区别的。

三个面向区别

-面向对象是指,我们考虑问题时,以对象为单位,考虑它的属性及方法.
-面向过程是指,我们考虑问题时,以一个具体的流程(事务过程)为单位,考虑它的实现.
-接口设计与非接口设计是针对复用技术而言的,与面向对象(过程)不是一个问题.更多的体现就是对系统整体的架构

使用注解开发

1 注解在接口方法上实现
//    查询所有用户
@Select("select * from users")
List<User> getList();
2 核心配置文件中绑定接口
<mappers>	
	<mapper class="com.dao.UserMapper.class"/>
mappers>

本质:反射机制实现

底层:动态代理

接口的方法中,如果参数多于1个,每个基本类型参数前必须加上@pamar

 //    查询所有用户 
 @Select("select * from users where id = #{id},pwd = #{pwd}") 
 List<User> getList(@Param("id") int id,@Param("pwd") String password);

如果是引用类型,不用写@Param注解,直接写其中的属性名即可

11、参数

多个参数 使用@Param方式

​ 当Dao接口方法多个参数,需要通过名称使用参数。在方法形参前面加入@Param(“自定义参数名")mapper文件使用#{自定义参数名}。

​ 例如定义: List selectStudent(@Param("personName") String name ) { ...}
​ mapper文件: select * from student where name = #{ personName}

​ 接口方法:
List selectMultiParam(@Param( "personName") String name, ​ @Param ( "personAge") int age);
mapper 文件:

<select id="selectMultiParam" resultType="com.wei.domain.Users">	
	select * from users
    where phone=#{personName} or password=#{password}
select>

多个参数 使用对象方式传

​ 使用java对象传递参数,java的属性值就是sql需要的参数值。每一个属性就是一个参数。

​ 语法格式:#{ 对象中的属性名,javaType = java中数据类型名, jdbcType = 数据类型名称 }
javaType, jdbcType 的类型MyBatis可以检测出来,一般不需要设置。常用格式 #{ 对象中的属性名 }

多个参数 按位置

​ 参数位置从0开始,引用参数语法 # arg位置},第一个参数是#{arg0},第二个是#{arg1}

注意: mybatis-3.3版本和之前的版本使用#{0},#{1}方式,从mybatis3.4开始使用#{arg0}方式。

​ 接口方法:

List<User> selectByPhoneAndPwd(String phone,String pwd);

mapper文件

<select id="selectByPhoneAndPwd" resultType="com.wei.domain.Users">	
select * from users where phone=#{arg0} or password= #{arg1}
select>

多个参数 使用map

​ Map集合可以存储多个值,使用Map向mapper文件一次传入多个参数。Map集合使用String的 key,object类型的值存储参数。mapper文件使用# { key }引用参数值。
例如:`

Map<String,String> data = new HashMap<String,String>();
data.put("myphone","111222333");
data.put("mypwd","111222111");

接口方法:
List selectMultiMap(Maphap) ;

mapper文件:

<select id="selectNultiMap" resultType="com.wei.domain.User">	
	select id,name , email,age from student 
	where phone=#{myphone} or password=#(mypwd}
select>

# 和 $

# 占位符,告诉mybatis使用实际的参数值代替。并使用PrepareStatement对象执行sql 语句, #{…}代替sql语句的“?”。这样做更安全,更迅速,通常也是首选做法

mapper文件

<select id="selectById" resultType="com.wei.domain.User">	
	select * from users where id = #{uid}
select>

转为MyBatis 的执行是:
String sql = ” select * from users where id=? ";
PreparedStatement ps = conn.prepareStatement(sql);
uid的值如假设为1005
ps.setInt(1,1005);
解释:
where id = ? 就是 where id = #{uid}
ps.setInt(1,1005) , 1005会替换掉 #{uId}

$ 字符串替换,告诉mybatis使用$包含的“字符串”替换所在位置。使用Statement把 sql语句和${}的内容连接起来。主要用在替换表名,列名,不同列排序等操作。

使用# select * from users where id=#{uid}

#的结果:select* from users where id=?

使用$ select * from users where id=${uid}

$的结果:select * from users where id=1001

​ string sql="select * from users where id= " + “1001”;

总之:使用$的statement对象执行sql,效率比Preparedstatement低
$ :可以替换表名或者列名,你能确定数据是安全的。可以使用$

# 优点:

  • #使用?在sql语句中做站位的,使用Preparedstatement执行sql,效窣高
  • #能够避免sql注入,更安全

$ 缺点:

  • $ 不使用占位符,是字符串连接方式,使用statement对象执行sql,效率低
  • $ 有sql注入的风险,缺乏安全性
  • $ :可以替换表名或者列名

12、封装MyBatis的输出结果

使用resultType

resultType结果类型,指sql语句执行完毕后,数据转为的java对象。

处理方式:

  • 1、mybatis执行sql语句,然后mybatis调用类的无参数构造方法,创建对象。
  • 2、mybatis把Resultset指定列值付给同名的属性。

注意:resultType 和 resultMap,不能同时使用。

对等的jdbc
Resultset rs = executeQuery (" select* from users" );
while (rs.next(){
User user = new User();
User .setId(rs.getInt(“id”));
User.setPhone (rs.getstring ( “phone” ) );
User.setPassword (rs.getstring ( “password” ) );
}

//需要有set方法

简单类型

接口方法:

int countUser();

mapper 文件:

<select id="countStudent" resultType="int"> 	
	select count(*) from users 
select>

resultType结果类型:1、类型的全限定名 2、类型的别名

自定义类型的别名

在mybatis的主配置文件中配置,使用标签来定义或者使用来定义

<typeAliases>
  
  <typeAlias type="" alias=""/>
  typeAliases>
<typeAliases>   
 
	<package name="com.wei.dao"/>
typeAliases>
返回Map

sql的查询结果作为Map 的 key 和 value。推荐使用Map

注意:Map作为接口返回值,sql语句的查询结果最多只能有一条记录。大于一条记录是错误。

resultMap

结果映射,指定列名h额java对象的属性对应关系

可以自定义列值赋值给那个java属性

当列名和属性名不一样时,一定要使用resultMap来指定

接口方法

List<Student> selectMap();

mapper.xml

<select id="selectMap" resultMap="userMap"> 
  select * from users		
 select>
 
 	<resultMap id="userMap" type="com.wei.dao.User">  
 	      
 	    <id column="id" property="id"/>
 	           
 	    <result column="phone" property="phone">
 	    <result column="password" property="password">
    resultMap>

属性名和列名不同的处理方式

1、使用列别名+resultType

2、使用resultMap

模糊查询 like

1、在java中指定号like的内容,如 %韦%

2、在mapper中拼接like的内容,注意:拼接不要用+

13、Mybatis核心配置文件

层级关系

  • configuration(配置)
    • properties(属性)
    • settings(设置)
    • typeAliases(类型别名)
    • typeHandlers(类型处理器)
    • objectFactory (对象工厂)
    • plugins(插件)
    • environments (环境配置)
      • environment(环境变量)
      • transactionManager(事务管理器)
      • datasource(数据源)
    • databaseIdProvider(数据库厂商标识)
    • mappers(映射器)

Mybatis学习笔记_第4张图片

environments (环境配置)

其中实物管理的类型有两种
  • JDBC:这个配置就是直接使用了JDBC的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。
  • MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如JEE应用服务器的上下文)。默认情况下它会关闭连接,然而一些容器并不希望这样,因此需要将closeConnection属性设置为false来阻止它默认的关闭行为。
其中数据源的类型有三种
  • UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭连接。
  • POOLED:这种数据源的实现利用“池”的概念将JDBC连接对象组织起来。
  • JNDI:这个数据源的实现是为了能在如EJB或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的引用。

properties(属性)

可以通过properties属性来实现引用配置文件

这些属性都是可外部配置且可动态替换的,既可以在典型的Java属性文件中配置,亦可通过properties元素的子元素来传递。

Mybatis学习笔记_第5张图片

<properties resource="db.properties">	
  
  <property name="jdbc.username" value="abc"/>	
  <property name="jdbc.password" value="abc123"/>
properties>	
  • 如果外部配置文件和内部配置中有相同字段,优先使用外部的!

typeAliases(类型别名)

​ 类型别名是为Java类型设置一个短的名字,它只和XML配置有关,存在的意义仅在于用来减少类完全限定名的冗余,例如:

在核心配置文件中为User类起一个别名


<typeAliases> 
   <typeAlias type="com.wei.domain.User" alias="User"/>
typeAliases>

此时就可以在Mapper文件中使用了,之前的com.wei.domain.User就可以写成user

<select id="findall" resultType="user">     
	select * from users;
select>

也可以指定一个包名,MyBatis 会在包名下面搜索需要的Java Bean,比如:

扫描实体类的包,它的默认别名就为这个类的类名首字母小写(其实大写也行)!

 

<typeAliases>    
	<package name="com.wei.domain"/>
typeAliases>

此时在Mapper文件中com.wei.domain.User也可以直接写成user


<select id="getList" resultType="user">  
  select * from users
select>

如果非要再改别名,需要在实体类上写注解

@Alias("myuser")
public class User(){...}

settings(设置)

这是MyBatis 中极为重要的调整设置,它们会改变MyBatis 的运行时行为。

日志的加载:


<settings>    
	<setting name="logImpl" value="STDOUT_LOGGING">
settings>

mappers(映射器)

该标签的作用是加载映射的,加载方式有如下几种:

方式一:使用resource绑定注册

相对于类路径的资源引用

<mappers>
	<mapper resource="com/dao/UserMapper.xml"/>
mappers>
方式二:使用class文件绑定注册
<mappers>
	<mapper class="com.dao.UserMapper.xml"/>
mappers>

使用classs注意:

  • 接口和它的Mapper配置文件必须同名
  • 必须在同一个包下
方式三:使用扫描包绑定注册
<mappers>
	<mapper package="com.dao"/>
mappers>

使用package注意:

  • 接口和它的Mapper配置文件必须同名
  • 必须在同一个包下
方式四:使用URL绑定注册

完全限定资源定位符(URL)

<mappers>
	<mapper url:"磁盘中的文件路径"/>
mappers>

14、多表操作

一对一

Mapper文件

	<resultMap id="orderMap" type="com.wei.domain.Order">   
	
        <id column="oid" property="id">id>
        <result column="ordertime" property="ordertime">result>        			      
        <result column="total" property="total">result>
	
	
	                
		<association property="user" javaType="com.wei.domain.User">            	
		<id column="uid" property="id">id>
		<result column="phone" property="phone">result>
		<result column="passwrod" property="password">result>        	
		association>
	resultMap>
	
	<select id="findByCondition" parameterType="com.wei.domain.User" 	
								resultMap="orderMap">
	    select * ,o.id oid from orders o, users u where o.uid = u.id    
	select>

属性是一个对象就用association,如果是集合用constructor

一对多

查看用户有哪些订单order

	<resultMap id="userMap" type="com.wei.domain.User">
        
        <id column="oid" property="id">id>
        <result column="phone" property="phone">result>
        <result column="password" property="password">result>
        
        <constructor property="orderList" ofType="com.wei.domain.Order">
            
            <id column="oid" property="id">id>
            <result column="ordertime" property="ordertime">result>
            <result column="total" property="total">result>
        constructor>

    resultMap>

    <select id="findByCondition" parameterType="com.wei.domain.User" resultMap="userMap">
        select * ,o.id oid from orders o, users u where o.uid = u.id
    select>

15、缓存

查询数据库耗费资源,一次查询结果暂存在一个可以直接取到的地方,再次查询相同数据时,直接从缓存中取

什么是缓存?
  • 存在内存中的临时数据。

  • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。

为什么使用缓存?
  • 减少和数据库的交互次数,减少系统开销,提高系统效率。
什么样的数据能使用缓存?
  • 经常查询并且不经常改变的数据。

  • MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。

  • MyBatis系统中默认定义了两级缓存:一级缓存二级缓存

    • 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)
    • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存、
    • 为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

一级缓存

也叫本地缓存(SqlSession),与数据库同一次会话期间查询到的数据会放在本地缓存中。以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库;

步骤:

  • 1、开启日志
  • 2、测试在一个Session中查询两次相同记录
  • 3、查看日志输出
    Mybatis学习笔记_第6张图片
缓存失效的情况
  • 映射语句文件中的所有select语句的结果将会被缓存
  • 映射语句文件中的所有insert、update和delete语句会刷新缓存
  • 缓存会使用最近最少使用算法 (LRU,Least Recently Used)算法来清除不需要的缓存
  • 缓存不会定时进行刷新(也就是说,没有刷新间隔)
  • 缓存会保存列表或对象(无论查询方法返回哪种)的1024个引用
  • 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改

二级缓存

  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存;
  • 工作机制
    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
    • 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
    • 新的会话查询信息,就可以从二级缓存中获取内容;
    • 不同的mapper查出的数据会放在自己对应的缓存(map)中;

步骤:

  • 1、在核心配置文件中开启全局缓存
<setting name="cacheEnable" value="true">
  • 2、在指定宁的Mapper文件中使用二级缓存
<cache 
	eviction="FIFO" 
	flushInterval="60000"
	size="512" 
	readonly="true"/>
 <select id="getList" resultType="user" useCache="true">      
 	select * from users
 select>

这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。

可用的清除策略有:

  • LRU – 最近最少使用:移除最长时间不被使用的对象。
  • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
  • WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。

默认的清除策略是 LRU。

你可能感兴趣的:(java,数据库,mybatis)