Mybatis学习笔记

Mybatis学习笔记

1、简介

1.1、Mybatis:

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

如何获取mybatis?

  • maven仓库

    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.2</version>
    </dependency>
    
  • github

1.2、持久化

数据持久化

持久化就是将程序的数据在持久状态和瞬时状态转化的过程

内存:断电即失

数据库(jdbc)、io文件持久化

为什么要持久化?

有一些对象不能丢掉

内存太贵了

1.3、持久层

Dao层、Service层、Colltroller层

完成持久化工作的代码块

层界限十分明显

1.4、为什么需要mybatis

  • 方便

  • 传统的jdbc代码太复杂了,简化、框架、自动化

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

  • 不用mybatis也可以,更容易上手技术,没有高低之分

  • 优点:

    1. 简单易学

    2. 灵活

    3. 解除SQL与Java代码的耦合

    4. 提供映射标签,提供对象与数据库的orm字段关系映射

    5. 提供对象关系映射标签,支持对象关系组建维护

    6. 提供xml标签,支持编写动态SQL

      最重要的一点:使用的人多!

2、第一个mybatis程序

搭建环境->导入mybatis->编写代码->测试

2.1、搭建环境

2.1.1、搭建数据库
-- DROP database IF EXISTS `bank`;
-- create database `bank`;
use `user`;
SET NAMES utf8;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `account`;
CREATE TABLE `account` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL DEFAULT '' COMMENT '姓名',
  `money` decimal NOT NULL DEFAULT 0.0 COMMENT '余额',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

BEGIN;
INSERT INTO `account` VALUES 
('1', '周嘉川',  100000), 
('2', '季樱', 3000), 
('3', '朱律',20310), 
('4', '纪和琅', 10235), 
('5', '初凝', 52410);
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;

2.1.2、新建一个maven项目,删除src目录

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
<!--父工程-->
    <groupId>com.tina</groupId>
    <artifactId>mybatisstart</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <junit.version>4.12</junit.version>
        <mysql.version>8.0.19</mysql.version>
        <mybatis.version>3.5.2</mybatis.version>
    </properties>

<!--导入依赖-->
<dependencies>
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>${mybatis.version}</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>${mysql.version}</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>${junit.version}</version>
        <scope>test</scope>
    </dependency>
</dependencies>

</project>

2.1.3、创建一个模块

2.1.3.1、编写mybatis的核心配置文件
<?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">
<!--核心配置文件-->
<configuration>
    <environments default="development">
        <environment id="development">
<!--            事务管理-->
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url"
                          value="jdbc:mysql://localhost:3306/user?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false&amp;serverTimezone = GMT
"/>
                <property name="username" value="root"/>
                <property name="password" value="password"/>
            </dataSource>
        </environment>
    </environments>
<!--    每一个Mapper.xml都需要在mybatis核心配置文件中注册-->
    <mappers>
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>
2.1.3.2、编写mybatis核心配置类
package com.tina.utils;

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;

/**
 * @author SongTiantian
 * @create 2021-05-11-11:46
 */
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();
        }
    }
    
    //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
    // SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
    // 你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}
2.1.3.2、编写代码
实体类
package com.tina.pojo;

/**
 * @author SongTiantian
 * @create 2021-05-11-11:57
 */
public class User {
    private int id;
    private String name;
    private String country;

    public User() {
    }

    public User(int id, String name, String country) {
        this.id = id;
        this.name = name;
        this.country = country;
    }

    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 getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", country='" + country + '\'' +
                '}';
    }
}
Dao接口
public interface UserDao {
    List<User> getUserList();
}
接口实现类由原来的UserDaoImpl转换为一个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=绑定的一个Mapper接口-->
<mapper namespace="com.tina.Dao.UserDao">
<!--    查询语句-->
    <select id="getUserList" resultType="com.tina.pojo.User" >
        select * from user.user
    </select>
</mapper>
测试:
package com.tina.dao;

import com.tina.Dao.UserDao;
import com.tina.pojo.User;
import com.tina.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;

/**
 * @author SongTiantian
 * @create 2021-05-12-12:11
 */
public class UserTest {
    @Test
    public void testUserDao (){
//        获取sqlSession对象
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
//        getMapper
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        List<User> userList = mapper.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }
        //关闭sqlSession
        sqlSession.close();
    }
}

结果:

在这里插入图片描述

3、CRUD

3.1、namespace

namespace中的包名要和Dao或mapper接口的包名一致

3.2、select:选择、查询语句

id:就是对应的namespace中的方法名

resultType:SQL语句执行的返回值

parameterType:参数类型

编写接口

编写对应mapper中的SQL语句

测试

3.3、insert

3.4、update

3.5、delete

注意点:增删改需要提交事务

3.6、map

Map传递参数,直接在SQL中取出key即可

对象传递参数,直接在SQL中取出对象的属性即可

只有一个基本参数的情况下,可以直接在SQL中取到

多个参数用map或者注解

3.7模糊查询

在SQL拼接中使用通配符

4、配置解析

4.1、核心配置文件

mybatis-config.xml

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

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

4.2、environments(环境配置)

mybatis可以配置成适应多种环境,但是每个sqlSessionFactory实例只能选择一种环境

mybatis的默认事务管理器是jdbc,连接池POOLED

4.3、properties(属性)

在xml中,所有标签都要规定其顺序,properties只能放到最上面

The content of element type “configuration” must match “(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)”.

4.4、typeAliases(类型别名)

类型别名是为Java类型设计的一个短的名字

存在的意义仅在于用来减少类完全限定名的冗余

mybatis-config.xml

<!--    可以给实体类起别名-->
<typeAliases>
    <typeAlias type="com.tina.pojo.User" alias="user"></typeAlias>
</typeAliases>


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

<!--    可以给实体类起别名-->
<typeAliases>
    <package name="com.tina.pojo"/>
</typeAliases>

扫描实体类的包,它的默认别名就为这个类的别名,首字母小写!

实体类比较少的时候,使用第一种方法,

如果实体类十分多,建议使用第二种。

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

@Alias("user")

mapper.xml

<select id="getUserList" resultType="User" >
    select * from user.user
</select>

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

4.5、settings(设置)

4.6、其他设置

typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)

  • mybatis-generator-core

  • mybatis-plus

  • 通用mapper

4.7、mappers(映射器)

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

<!-- 推荐使用
使用相对于类路径的资源引用 
-->
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  <mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 不建议使用 -->
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
  <mapper url="file:///var/mappers/AuthorMapper.xml"/>
  <mapper url="file:///var/mappers/BlogMapper.xml"/>
  <mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 
注意点:
接口和它的配置文件必须同名
接口和它的配置文件必须在同一个包下
-->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 
注意点:
接口和它的配置文件必须同名
接口和它的配置文件必须在同一个包下
-->
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>

4.8、生命周期和作用域

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

SqlSessionFactoryBuilder

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

SqlSessionFactory

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

SqlSession

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

其中的每一个mapper都代表一个业务

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

5.1、问题

数据库中的字段
在这里插入图片描述

新建一个项目,拷贝之前的,测试实体类字段不一致的情况

public class User {
    private int id;
    private String username;
    private String count;
}

测试出现问题:
在这里插入图片描述

5.2、解决方法:

方法一:起别名
select id, name as username ,country as count  from user.user where id = #{id}
方法二:使用resultMap结果集映射

resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份 resultMap 能够代替实现同等功能的数千行代码。

ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。

 <resultMap id="userMap" type="user">
<!--        column代表数据库中的字段,property代表实体类中的属性-->
        <result column="id" property="id"></result>
        <result column="name" property="username"></result>
        <result column="country" property="count"></result>
    </resultMap>
<select id="getUserById" resultMap="userMap"  parameterType="int">
    select * from user.user where id = #{id}
</select>

ResultMap 的优秀之处——你完全可以不用显式地配置它们。

6、日志

6.1、日志工厂

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

曾经sout和debug是最常用的做法

设置名描述有效值默认值
logImpl指定 MyBatis 所用日志的具体实现,未指定时将自动查找。SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING未设置
  • SLF4J
  • LOG4J
  • LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • STDOUT_LOGGING
  • NO_LOGGING

在mybatis中,具体使用哪一个日志实现由我们的设置决定!

STDOUT_LOGGING 标准日志输出

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

测试结果:

在这里插入图片描述

6.2、LOG4J

  • Log4j是Apache的一个开源项目
  • 通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,
  • 我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
  • 最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

先导入LOG4J 的包

<log4j.version>1.2.17</log4j.version>
<!-- 日志文件管理包 -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>${log4j.version}</version>
</dependency>

在使用log4j的类中,导入import org.apache.log4j.Logger;

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

static Logger log = Logger.getLogger(UserLog.class);

日志级别:

log.info("hello log4j info\n");
log.warn("hello log4j warn\n");

7、分页

为什么要分页?

减少数据的处理量

select * from user limit 0,5;

7.1、使用mybatis实现分页,核心是SQL

7.1.1、接口
List<User> getUserByLimit(Map<String, Integer> map);
7.1.2、Mapper.xml
<select id="getUserByLimit" resultType="user" parameterType="map" resultMap="userMap">
    select * from user limit #{startIndex},#{pageSize};
</select>
7.1.3、测试
  @Test
    public void testGetUserByLimit(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        HashMap<String, Integer> hashMap = new HashMap<>();
        hashMap.put("startIndex",2);
        hashMap.put("pageSize",2);
        List<User> users = mapper.getUserByLimit(hashMap);
        for (User user : users) {
            System.out.println(user);
        }
        sqlSession.close();
    }

7.2、RowBounds分页

7.3、分页插件Mybatis PageHelper

8、使用注解开发

8.1、面向接口编程

什么叫面向接口编程

在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了;而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程。

1.关于接口的理解。

接口从更深层次的理解,应是定义(规范,约束)与实现(名实分离的原则)的分离。

接口的本身反映了系统设计人员对系统的抽象理解。

接口应有两类:第一类是对一个个体的抽象,它可对应为一个抽象体(abstract class);

第二类是对一个个体某一方面的抽象,即形成一个抽象面(interface);

一个体有可能有多个抽象面。

抽象体与抽象面是有区别的。

2.设计接口的另一个不可忽视的因素是接口所处的环境(context,environment),系统论的观点:环境是系统要素所处的空间与外部影响因素的总和。任何接口都是在一定的环境中产生的。因此环境的定义及环境的变化对接口的影响是不容忽视的,脱离原先的环境,所有的接口将失去原有的意义。

3.按照组件的开发模型(3C),它们三者相辅相成,各司一面,浑然一体,缺一不可。

面向对象是指,我们考虑问题时,以对象为单位,考虑它的属性及方法

面向过程是指,我们考虑问题时,以一个具体的流程(事务过程)为单位,考虑它的实现

接口设计与非接口设计是针对复用技术而言的,与面向对象(过程)不是一个问题

UML里面所说的interface是协议的另一种说法。并不是指com的interface,CORBA的interface,Java的interface,Delphi的interface,人机界面的interface或NIC的interface。

在具体实现中,是可以把UML的interface实现为语言的interface,分布式对象环境的interface或其它什么interface,但就理解UML的interface而言,指的是系统每部分的实现和实现之间,通过interface所确定的协议来共同工作。

面向interface编程,原意是指面向抽象协议编程,实现者在实现时要严格按协议来办。面向对象编程是指面向抽象和具象。抽象和具象是矛盾的统一体,不可能只有抽象没有具象。一般懂得抽象的人都明白这个道理。 但有的人只知具象却不知抽象为何物。  所以只有interface没有实现,或只有实现而没有interface者是没有用的,反OO的。

所以还是老老实实面向对象编程,面向协议编程,或者什么都不面向,老老实实编程。

根本原因:解耦

8.2、注解开发

底层主要用到反射

8.1、注解在接口上实现
//查询全部用户
@Select("select * from user")
List<User> getUserList();
8.2、需要在配置文件中绑定接口
<!--绑定接口-->
<mappers>
    <mapper class="com.tina.Dao.UserDao"></mapper>
</mappers>
8.3、CRUD

接口

public interface UserDao {

    //查询全部用户
    @Select("select * from user")
    List<User> getUserList();
    //根据id查询用户
    @Select("select * from user where id = #{id}")
    User getUserById(@Param("id") int id);
    @Update("update user set name=#{name} ,country=#{country} where id = #{id}")
    int updateUser(User user);
    @Insert("insert into user(name,country) values(#{name},#{country})")
    int addUser(User user);
    @Delete("delete from user where id = #{id}")
    int deleteUser(@Param("id") int id);


}

测试方法

    @Test
    public void testUserOne (){
//        获取sqlSession对象
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
//        getMapper
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        mapper.updateUser(new User(12,"朱律","CN"));
//        mapper.addUser(new User(6,"谢期","USB"));
//        mapper.deleteUser(10);
        sqlSession.commit();
//        User user = mapper.getUserById(3);
//            System.out.println(user);
        //关闭sqlSession
        sqlSession.close();
    }

也可以在创建工具类时自动提交事务

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

**注意:**我们必须将接口注册绑定到核心配置文件中

<mappers>
    <mapper class="com.tina.Dao.UserDao"></mapper>
</mappers>

关于@Param()注解

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值