01 MyBatis学习笔记

MyBatis学习教程

1、简介

1.1 介绍

  • MyBatis是一款优秀的持久层框架
  • 它支持定制化SQL、存储过程以及高级映射
  • MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集
  • MyBatis可以使用简单的XML或注解来配置和映射原生类型、接口和Java的POJO(Plain Old Java Objects,普通老式Java对象)为数据库中记录
  • MyBatis本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis
  • 2013年迁移到了Github

1.2 持久化

数据持久化

  • 持久化就是将程序的数据在持久状态和瞬时状态转化的过程
  • 内存:断电即失
  • 数据库(Jdbc),io文件持久化

为什么需要持久化?

  • 有一些对象,不能让他丢掉
  • 内存太贵了

1.3 持久层

Dao层、Service层、Controller层…

  • 完成持久化工作的代码块
  • 层界限十分明显

1.4 为什么需要MyBatis

  • 帮助程序员将数据存入到数据库
  • 方便
  • 传统的JDBC代码太复杂。简化、自动化
  • 容易上手
  • 优点:
    • 简单易学
    • 灵活
    • sql和代码的分离,提高了可维护性
    • 提供映射标签,支持对象与数据库的orm字段关系映射
    • 提供对象关系映射标签,支持对象关系组件维护
    • 提供xml标签,支持编写动态sql

2. Hello World

思路:搭建环境–>导入MyBatis–>编写代码–>测试

2.1 搭建环境

  • 搭建数据库:
CREATE DATABASE `mybatis`;
USE `mybatis`;
CREATE TABLE `user`(
`id` INT(20) NOT NULL PRIMARY KEY,
`name` VARCHAR(30) DEFAULT NULL,
`pwd` VARCHAR(20) DEFAULT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `user`(`id`,`name`,`pwd`) VALUES
  (1,'老二','123'),
  (2,'张三','123'),
  (3,'李四','123'),
  (4,'王五','123')
  • 搭建maven项目
<dependencies>
    <!--mysql驱动-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
    <!--mybatis-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.6</version>
    </dependency>
    <!-- junit-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
</dependencies>
  • 编写MyBatis工具类
public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static{
        try{
            //获取sqlSessionFactory对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        }catch (IOException e){
            e.printStackTrace();
        }

    }

    public static SqlSession getSqlSession(){
       return sqlSessionFactory.openSession();
    }

}

2.3 编写代码

  • 实体类

    public class User {
        private int id;
        private String name;
        private String pwd;
    
        public User() {
        }
    
        public User(int id, String name, String pwd) {
            this.id = id;
            this.name = name;
            this.pwd = pwd;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getPwd() {
            return pwd;
        }
    
        public void setPwd(String pwd) {
            this.pwd = pwd;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", pwd='" + pwd + '\'' +
                    '}';
        }
    }
    
  • Dao接口

    public interface UserDao {
        List<User> getUserList();
    }
    
  • 接口实现类(由原来的Impl实现类转变为Mapper配置文件)

    <?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绑定一个对应的Dao/Mapper接口-->
    <mapper namespace="org.mybatis.example.BlogMapper">
        <select id="getUserList" resultType="com.xdu.pojo.User">
          select * from mybatis.user;
        </select>
    </mapper>
    

2.4 测试

注意点:

org.apache.ibatis.builder.BuilderException

MapperRegistry是什么?

每一个Mapper.xml都需要在MyBatis核心配置文件中注册

<mappers>
	<mapper resource="com/xdu/utils/MybatisUtils"/>
</mappers>

java.lang.ExceptionInInitializerError

Maven由于约定大于配置,解决办法:

<build>
	<resources>
    	<resource>
        	<directory>src/main/resources</directory>
            <includes>
            	<include>**/*.properties</include>
            	<include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
        <resource>
        	<directory>src/main/java</directory>
            <includes>
            	<include>**/*.properties</include>
            	<include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

2.5 CRUD

重复上面的操作

  1. 设定Mapper接口
  2. 接口实现,编写Mapper.xml,设置SQL语句
  3. 编写测试类进行测试
  • Mapper接口:

    public interface UserMapper {
        List<User> getUserList();
    
        List<User> getUserById(int id);
    
        int addUser(User user);
    
        int updateUser(User user);
    
        int deleteUser(int id);
    }
    
  • Mapper实现

    <mapper namespace="com.xdu.dao.UserMapper">
        <select id="getUserList" resultType="com.xdu.pojo.User">
            select * from mybatis.user;
        </select>
    
        <select id="getUserById" parameterType="int" resultType="com.xdu.pojo.User">
            select * from mybatis.user where id = #{id};
        </select>
        
        <insert id="addUser" parameterType="com.xdu.pojo.User">
            insert into mybatis.user (id, name, pwd) values (#{id},#{name},#{pwd});
        </insert>
    
        <update id="updateUser" parameterType="com.xdu.pojo.User">
            update mybatis.user set name=#{name}, pwd=#{pwd} where id=#{id};
        </update>
    
        <delete id="deleteUser" parameterType="int">
            delete from mybatis.user where id=#{id};
        </delete>
    </mapper>
    
  • 测试:

        //测试插入(增删改需要提交事务)
        @Test
        public void addUser(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            mapper.addUser(new User(5,"老六","123"));
            System.out.println();
            sqlSession.commit();
            sqlSession.close();
        }
    
        //测试update
        @Test
        public void updateUser(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            int flag = mapper.updateUser(new User(3,"三哥","1234"));
            System.out.println(flag);
            sqlSession.commit();
            sqlSession.close();
        }
    
    //    测试删除
        @Test
        public void deleteUser(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            mapper.deleteUser(5);
            sqlSession.commit();
        	sqlSession.close();
        }
    
    

3. 万能的Map

假设,实体类或者数据库的表,字段或者参数过多,我们应当使用Map!

例如以下例子:

在Mapper接口中定义:

int addUserByMap(Map<String,Object> map);

在Mapper实现类中定义:

<insert id="addUserByMap" parameterType="map">
	insert into mybatis.user(id, name, pwd) values (#{userid},#{username},#{userpwd});
</insert>

测试类:

public void addUserByMap(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    Map<String, Object> map = new HashMap<String, Object>();
    map.put("userid",5);
    map.put("username","哇哈");
    map.put("userpwd","123");

    mapper.addUserByMap(map);
    sqlSession.commit();
    sqlSession.close();
}

Map传递参数,直接在sql中取出key即可!【parameterType=“map”】

对象传递参数,直接在sql中取对象的属性即可!【parameterType=“Object”】

只有一个基本类型参数的情况下,可以直接在sql中取出

多个参数用Map或者注解

4. 模糊查询

  • Java代码执行的时候,传递通配符% %

    List<User> user = mapper.getUserList(“%王%”);

  • 在sql拼接中使用通配符

    select * from user where name like "%"#{value}"%"

5.配置解析

5.1核心配置文件

  • mybatis-config.xml

  • MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息

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

5.2 环境配置(enviroments)

Mybatis可以配置成适合多种环境

MyBatis默认的事务管理器就是JDBC,连接池:POOLED

5.3 属性(properties)

这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。【db.properties】

db.properties文件中配置如下所示:

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8
username=root
password=password

mybatis-config.xml文件中配置如下所示

<properties resource="db.properties"/>

5.4 类型别名(typeAliases)

  • 类型别名是为Java类型设置一个短的名字
  • 存在的意义仅在于用来减少类完全限定名的冗余

类别名:

<typeAliases>
  <typeAlias alias="Author" type="domain.blog.Author"/>
  <typeAlias alias="Blog" type="domain.blog.Blog"/>
  <typeAlias alias="Comment" type="domain.blog.Comment"/>
  <typeAlias alias="Post" type="domain.blog.Post"/>
  <typeAlias alias="Section" type="domain.blog.Section"/>
  <typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>

包别名:

<typeAliases>
  <package name="domain.blog"/>
</typeAliases>

每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。

第一种可以DIY别名,第二种则不行,非要改的话,需要在实体类上增加注解

@Alias("author")
public class Author {
    ...
}

下面是一些为常见的 Java 类型内建的类型别名。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。

别名映射的类型
_bytebyte
_longlong
_shortshort
_intint
_integerint
_doubledouble
_floatfloat
_booleanboolean
stringString
byteByte
longLong
shortShort
intInteger
integerInteger
doubleDouble
floatFloat
booleanBoolean
dateDate
decimalBigDecimal
bigdecimalBigDecimal
objectObject
mapMap
hashmapHashMap
listList
arraylistArrayList
collectionCollection
iteratorIterator

5.5 映射器(mappers)

MapperRegistry:注册绑定我们的Mapper文件

方式一:

<!-- 使用相对于类路径的资源引用 -->
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
</mappers>

方式二:

<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
</mappers>

注意点:

  • 接口和它的Mapper配置文件必须同名
  • 接口和它的Mapper配置文件必须在同一个包下

方式三:

<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>

注意点:

  • 接口和它的Mapper配置文件必须同名
  • 接口和它的Mapper配置文件必须在同一个包下

5.6 作用域(Scope)和生命周期

依赖注入框架可以创建线程安全的、基于事务的 SqlSession 和映射器,并将它们直接注入到你的 bean 中,因此可以直接忽略它们的生命周期

SqlSessionFactoryBuilder

这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。

SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。

SqlSession

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。

6 解决属性名和字段名不一致的问题

问题

密码属性不一致!
在这里插入图片描述
在这里插入图片描述

解决办法:

  • 起别名

    select id,name,pwd as paaword from mybatis.user where id = #{id}

ResultMap

id为指定的sql语句标签的id,colum为数据库中的字段,property为实体类中的属性,

<resultMap id="UserMap" type="User">
    <result column="id" property="id"/>
    <result column="name" property="name"/>
    <result column="pwd" property="password"/>
  
</resultMap>

7. 日志工厂

<configuration>
  <settings>
    <setting name="logImpl" value="LOG4J"/>
  </settings>
</configuration>

value有多种,包括SLF4J、LOG4J、LOG4J2、JDK_LOGGING、COMMONS_LOGGING、STDOUT_LOGGING(标准的日志工厂格式)、NO_LOGGING

7.1 Log4J

介绍:是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件

  1. maven导包

  2. 建立资源文件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/kuang.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为日志的实现

    <settings>
    	<setting name="logImpl" value="LOG4J"/>
    </settings>
    
  4. 实现、使用

4.1 在要使用Log4j的类中,导入包 import org.apache.log4j.Logger

4.2 日志对象,参数为当前类的class

static Logger logge = Logger.getLogger(UserDaoTest.class)

4.3 使用,常用的有info、debug、error

8.分页

为什么分页?

ans:减少数据的处理量

  • 使用Limit分页

    select * from user limit startIndex,pageSize;
    
  • **使用Mybatis实现分页 **

    • 接口

      List<User> getUserByLimit(Map<String,Integer> map);
      
    • Mapper.xml

      <select id="getUserByLimit" parameterType="map" resultMap="UserMap">
      	select * from user limit #{startIndex},#{pageSize}
      </select>
      
    • 最后就是测试

  • RowBounds

    • Mapper接口

      List<User>  getUserByRowBounds();
      
    • Mapper.xml

      <select id="getUserByBounds" resultMap="Map">
          select * from mybatis.user;
      </select>    
      
    • Test

      #public void getUserByRowBounds(){
          SqlSession sqlSession = MybatisUtils.getSqlSession();
          //RowBounds方法实现
          RowBounds rowBounds = new BowBounds(1,2)
          List<User> = sqlSession.selectList("com.xdu.dao.UserMapper.getUserByBounds");
          for(User user : userList){
              System.out.println(user);
          }
          sqlSession.colse();
      }
      

8.2 分页插件 PageHelper

https://pagehelper.github.io/

9. 注解开发

  1. 注解在接口上实现

    public interface UserMapper {
    
        @Select("select * from user")
        List<User> getUser();
    }
    
  2. 需要在核心配置文件中绑定接口

    <mappers>
        <mapper class="com.xdu.dao.UserMapper"/>
    </mappers>
    
  3. 测试

    本质:反射机制实现

    底层:动态代理

9.1 CRUD

我们可以在工具类创建的时候实现自动提交事务

public static SqlSession getSqlSession(){
    return sqlSessionFactory.openSession(true);
}

编写接口,增加注解

public interface UserMapper {

    @Select("select * from user")
    List<User> getUser();

    //方法存在多个参数,参数前面增加@Param注解

    @Select("select * from user where id = #{uid}")
    List<User> getUserById(@Param("uid")int id);

    @Insert("insert into user(id,name,pwd) values (#{id},#{name},#{pwd})")
    int addUser(User user);

    @Update("update user set name=#{name},pwd=#{pwd} where id=#{id}")
    int updateUser(User user);

    @Delete("delete from user where id=#{u_id}")
    int deleteUser(@Param("u_id")int id);
}

测试类

【注意】将接口注册绑定到我们的核心配置文件中!

关于@Param()注解

  • 基本类型的参数或者String类型,需要加上
  • 引用类型不需要加
  • 如果只有一个基本类型的话,可以忽略,建议加上
  • 在SQL中引用的就是我们这里的@Param()中设定的属性名

10. Lombok

  1. 在idea中加入Lombok插件
  2. 在项目中加入Lombok包
Features
@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值