MyBatis友人帐之基础入门

一、简介

1.1什么是MyBatis

MyBatis 是一个开源的、轻量级的数据持久层框架,它可以简化 JDBC 的操作,让开发者只需要关注 SQL 语句本身,而不用处理加载驱动、创建连接、创建语句等繁琐的过程。

MyBatis 支持自定义 SQL、存储过程和高级映射,可以通过 XML 或注解来配置和映射原始类型、接口和 Java POJO(普通老式 Java 对象)为数据库中的记录。MyBatis 也提供了动态 SQL、类型别名、插件、缓存等功能,使得数据持久化更加灵活和高效

1.2持久化

持久化是将程序数据在持久状态和瞬时状态间转换的机制。

  • 即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件中、XML数据文件中等等。

  • JDBC就是一种持久化机制。文件IO也是一种持久化机制。

  • 在生活中 : 将鲜肉冷藏,吃的时候再解冻的方法也是。将水果做成罐头的方法也是。

为什么需要持久化服务呢?那是由于内存本身的缺陷引起的

  • 内存断电后数据会丢失,但有一些对象是无论如何都不能丢失的,比如银行账号等,遗憾的是,人们还无法保证内存永不掉电。

  • 内存过于昂贵,与硬盘、光盘等外存相比,内存的价格要高2~3个数量级,而且维持成本也高,至少需要一直供电吧。所以即使对象不需要永久保存,也会因为内存的容量限制不能一直呆在内存中,需要持久化来缓存到外存。

1.3持久层

什么是持久层?

  • 完成持久化工作的代码块 .  ---->  dao层 【DAO (Data Access Object)  数据访问对象】

  • 大多数情况下特别是企业级应用,数据持久化往往也就意味着将内存中的数据保存到磁盘上加以固化,而持久化的实现过程则大多通过各种关系数据库来完成。

  • 不过这里有一个字需要特别强调,也就是所谓的“层”。对于应用系统而言,数据持久功能大多是必不可少的组成部分。也就是说,我们的系统中,已经天然的具备了“持久层”概念?也许是,但也许实际情况并非如此。之所以要独立出一个“持久层”的概念,而不是“持久模块”,“持久单元”,也就意味着,我们的系统架构中,应该有一个相对独立的逻辑层面,专注于数据持久化逻辑的实现.

  • 与系统其他部分相对而言,这个层面应该具有一个较为清晰和严格的逻辑边界。【说白了就是用来操作数据库存在的!】

1.4Lombok介绍

Lombok 是一个 Java 库,可以通过注解的方式来简化 Java 代码,提高开发效率。它可以自动生成 getter、setter、equals、hashCode、toString 等方法,也可以自动化日志变量,还有一些其他的功能。Lombok 不仅是一个依赖 jar 包,也是一个 IDE 插件,它可以在编译时修改 AST(抽象语法树),从而改变字节码生成。

idea默认已集成Lombok

1.5 MyBatis-Plus

1.6MyBatis的优点

  • 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件就可以了,易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。

  • 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。

  • 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。

  • 提供xml标签,支持编写动态sql。

 二、环境配置与测试

2.1环境配置

 <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

可能出现问题说明:Maven静态资源过滤问题

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

2.2编写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.jdbc.Driver"/>


                <property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=false&amp;useUnicode=true&amp;characterEncoding=utf8&amp;serverTimezone=GMT"/>
                <property name="username" value="root"/>
                <property name="password" value="b123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/yanyu/dao/userMapper.xml"/>
    </mappers>
</configuration>

在使用mybatis连接MySQL数据库时,遇到这个问题:

com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

解决方案

在mybatis-config.xml配置文件中,修改useSSL属性为false

原因分析: SSL(Secure Sockets Layer 安全套接字协议),在mysql进行连接的时候,如果mysql的版本是5.7之后的版本必须要加上useSSL=false,mysql5.7以及之前的版本则不用进行添加useSSL=false,会默认为false,一般情况下都是使用useSSL=false,useSSL=true是进行安全验证,一般通过证书或者令牌什么的,useSSL=false就是通过账号密码进行连接。

2.3编写MyBatis工具类

package com.yanyu.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;

public class MybatisUtils {

    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //获取SqlSession连接
    public static SqlSession getSession(){
        return sqlSessionFactory.openSession();
    }

}

 2.4创建实体类

package com.yanyu.pojo;

import lombok.*;

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class User {

    private int id;  //id
    private String name;   //姓名
    private String pwd;   //密码

    //构造,有参,无参
    //set/get
    //toString()

}

2.5编写Mapper接口类

package com.yanyu.dao;

import com.yanyu.pojo.User;
import java.util.List;

public interface UserMapper {
    List<User> selectUser();
}

2.6编写Mapper.xml配置文件

<?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">
<mapper namespace="com.yanyu.dao.UserMapper">
    <select id="selectUser" resultType="com.yanyu.pojo.User">
        select * from user1
    </select>

</mapper>

2.7测试

package com.yanyu.dao;

import com.yanyu.pojo.User;
import com.yanyu.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class MyTest {
    @Test
    public void selectUser() {
        SqlSession session = MybatisUtils.getSession();
        //方法一:
        //List<User> users = session.selectList("com.kuang.mapper.UserMapper.selectUser");
        //方法二:
        UserMapper mapper = session.getMapper(UserMapper.class);
        List<User> users = mapper.selectUser();

        for (User user: users){
            System.out.println(user);
        }
        session.close();
    }
}

三、增删改查

3.1Mapper.xml中的命名空间及命名解析

Mybatis命名空间是一个用来区分不同映射文件中的SQL语句的标识符。命名空间可以是任意的字符串,通常是映射文件对应的接口类的全限定名,例如com.jianglei.example.bean.UserMapper。命名空间的作用有两个:

  • 一是可以避免SQL语句的ID冲突,因为每个SQL语句都是在命名空间中唯一的,而不是全局唯一的。例如,两个不同的映射文件中都可以有一个ID为findById的SQL语句,只要它们的命名空间不同即可。
  • 二是可以实现接口绑定,即让Mybatis自动根据接口方法生成代理对象,执行对应的SQL语句。这样可以省去手动编写代码,调用SqlSession的方法,提高开发效率和代码可读性。

3.2Select

选择,查询语句;
●id:就是对应的namespace中的方法名;
●resultType: Sq|语句执行的返回值!
●parameterType :参数类型! .

需求:根据id查询用户

1、在UserMapper中添加对应方法

public interface UserMapper {
   //查询全部用户
   List<User> selectUser();
   //根据id查询用户
   User selectUserById(int id);
}

2、在UserMapper.xml中添加Select语句

<select id="selectUserById" resultType="com.yanyu.pojo.User">
select * from user where id = #{id}
</select>

3、测试类中测试

@Test
public void tsetSelectUserById() {
   SqlSession session = MybatisUtils.getSession();  //获取SqlSession连接
   UserMapper mapper = session.getMapper(UserMapper.class);
   User user = mapper.selectUserById(1);
   System.out.println(user);
   session.close();
}

3.3insert

我们一般使用insert标签进行插入操作,它的配置和select标签差不多!

需求:给数据库增加一个用户

1、在UserMapper接口中添加对应的方法

//添加一个用户
int addUser(User user);

2、在UserMapper.xml中添加insert语句

<insert id="addUser" parameterType="com.ysnyu.pojo.User">
        insert into user1 (id,name,pwd) values (#{id},#{name},#{pwd})
    </insert>

3、测试

   @Test
    public void testAddUser() {
        SqlSession session = MybatisUtils.getSession();
        UserMapper mapper = session.getMapper(UserMapper.class);
        User user = new User(4,"李四","zxcvbn");
        int i = mapper.addUser(user);
        System.out.println(i);
        session.commit(); //提交事务,重点!不写的话不会提交到数据库
        session.close();
    }

注意点:增、删、改操作需要提交事务!

​​​​​​​3.4update

需求:修改用户的信息

1、同理,编写接口方法

//修改一个用户
    int updateUser(User user);

2、编写对应的配置文件SQL

<update id="updateUser" parameterType="com.yanyu.pojo.User">
        update user1 set name=#{name},pwd=#{pwd} where id = #{id}
    </update>

3、测试

@Test
    public void testUpdateUser() {
        SqlSession session = MybatisUtils.getSession();
        UserMapper mapper = session.getMapper(UserMapper.class);
        User user = mapper.selectUserById(1);
        user.setPwd("asdfgh");
        int i = mapper.updateUser(user);
        System.out.println(i);
        session.commit(); //提交事务,重点!不写的话不会提交到数据库
        session.close();
    }

3.5delete

我们一般使用delete标签进行删除操作,它的配置和select标签差不多!

需求:根据id删除一个用户

1、同理,编写接口方法

 //根据id删除用户
    int deleteUser(int id);

2、编写对应的配置文件SQL

 <delete id="deleteUser" parameterType="int">
        delete from user1 where id = #{id}
    </delete>

3、测试

 @Test
    public void testDeleteUser() {
        SqlSession session = MybatisUtils.getSession();
        UserMapper mapper = session.getMapper(UserMapper.class);
        int i = mapper.deleteUser(4);
        System.out.println(i);
        session.commit(); //提交事务,重点!不写的话不会提交到数据库
        session.close();
    }

3.6总结

小结:

  • 所有的增删改操作都需要提交事务!

  • 接口所有的普通参数,尽量都写上@Param参数,尤其是多个参数时,必须写上!

  • 有时候根据业务的需求,可以考虑使用map传递参数!

  • 为了规范操作,在SQL的配置文件中,我们尽量将Parameter参数和resultType都写上!

3.7map

1、在接口方法中,参数直接传递Map;

User selectUserByNP2(Map<String,Object> map);

2、编写sql语句的时候,需要传递参数类型,参数类型为map

<select id="selectUserByNP2" parameterType="map" resultType="com.kuang.pojo.User">
select * from user where name = #{username} and pwd = #{pwd}
</select>

3、在使用方法的时候,Map的 key 为 sql中取的值即可,没有顺序要求!

Map<String, Object> map = new HashMap<String, Object>();
map.put("username","小明");
map.put("pwd","123456");
User user = mapper.selectUserByNP2(map);

3.8模糊查询like语句

1、在接口方法中,参数直接传递Map;

List<User> getUserLike(String value);

2、编写sql语句的时候,需要传递参数类型

<select id="getUserLike" resultType="com.yanyu.pojo.User">
        select * from user1 where name like #{value}
    </select>

3.测试

   @Test
    public void testgetUserLike() {
        SqlSession session = MybatisUtils.getSession();  //获取SqlSession连接
        UserMapper mapper = session.getMapper(UserMapper.class);
        List<User> users = mapper.getUserLike("%李%");
        for (User user: users){
            System.out.println(user);
        }
        session.close();
    }

四、配置解析

4.1核心配置文件

核心配置文件

  • mybatis-config.xml 系统核心配置文件

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

  • 能配置的内容如下:

  1. configuration(配置)
  2. properties(属性)
  3. settings(设置)
  4. typeAliases(类型别名)
  5. typeHandlers(类型处理器)
  6. objectFactory(对象工厂)
  7. plugins(插件)
  8. environments(环境配置)
  9. environment(环境变量)
  10. transactionManager(事务管理器)
  11. dataSource(数据源)
  12. databaseIdProvider(数据库厂商标识)
  13. mappers(映射器)

<!-- 注意元素节点的顺序!顺序不对会报错 -->

4.2environments元素

<environments default="development">
 <environment id="development">
   <transactionManager type="JDBC">
     <property name="..." value="..."/>
   </transactionManager>
   <dataSource type="POOLED">
     <property name="driver" value="${driver}"/>
     <property name="url" value="${url}"/>
     <property name="username" value="${username}"/>
     <property name="password" value="${password}"/>
   </dataSource>
 </environment>
</environments>
  • 配置MyBatis的多套运行环境,将SQL映射到多个不同的数据库上,必须指定其中一个为默认运行环境(通过default指定)

  • 子元素节点:environment

    • dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。

    • 数据源是必须配置的。

    • 有三种内建的数据源类型

      type="[UNPOOLED|POOLED|JNDI]")
    • unpooled:这个数据源的实现只是每次被请求时打开和关闭连接。

    • pooled:这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来 , 这是一种使得并发 Web 应用快速响应请求的流行处理方式。

    • jndi:这个数据源的实现是为了能在如 Spring 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。

    • 数据源也有很多第三方的实现,比如dbcp,c3p0,druid等等....

    • 详情:点击查看官方文档

    • 这两种事务管理器类型都不需要设置任何属性。

    • 具体的一套环境,通过设置id进行区别,id保证唯一!

    • 子元素节点:transactionManager - [ 事务管理器 ]

<!-- 语法 -->
<transactionManager type="[ JDBC | MANAGED ]"/>

 4.3Properties优化

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

我们来优化我们的配置文件

第一步 ; 在资源目录下新建一个db.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT
username=root
password=b123456

第二步 : 将文件导入properties 配置文件

<configuration>
   <!--导入properties文件-->
   <properties resource="db.properties"/>

   <environments default="development">
       <environment id="development">
           <transactionManager type="JDBC"/>
           <dataSource type="POOLED">
               <property name="driver" value="${driver}"/>
               <property name="url" value="${url}"/>
               <property name="username" value="${username}"/>
               <property name="password" value="${password}"/>
           </dataSource>
       </environment>
   </environments>
   <mappers>
       <mapper resource="mapper/UserMapper.xml"/>
   </mappers>
</configuration>

●可以直接引入外部文件
●可以在其中增加一些属性配置
●如果两个文件有同一个字段,优先使用外部配置文件的!|

4.4别名优化

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

<!--配置别名,注意顺序-->
<typeAliases>
   <typeAlias type="com.yanyu.pojo.User" alias="User"/>
</typeAliases>

当这样配置时,User可以用在任何使用com.yanyu.pojo.User的地方。

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

<typeAliases>
   <package name="com.yanyu.pojo"/>
</typeAliases>

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

若有注解,则别名为其注解值。见下面的例子:

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

4.5设置

  • 设置(settings)相关 => 查看帮助文档

    • 懒加载

    • 日志实现

    • 缓存开启关闭

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

​​​​​​​

作用域理解

  • SqlSessionFactoryBuilder 的作用在于创建 SqlSessionFactory,创建成功后,SqlSessionFactoryBuilder 就失去了作用,所以它只能存在于创建 SqlSessionFactory 的方法中,而不要让其长期存在。因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。

  • SqlSessionFactory 可以被认为是一个数据库连接池,它的作用是创建 SqlSession 接口对象。因为 MyBatis 的本质就是 Java 对数据库的操作,所以 SqlSessionFactory 的生命周期存在于整个 MyBatis 的应用之中,所以一旦创建了 SqlSessionFactory,就要长期保存它,直至不再使用 MyBatis 应用,所以可以认为 SqlSessionFactory 的生命周期就等同于 MyBatis 的应用周期。

  • 由于 SqlSessionFactory 是一个对数据库的连接池,所以它占据着数据库的连接资源。如果创建多个 SqlSessionFactory,那么就存在多个数据库连接池,这样不利于对数据库资源的控制,也会导致数据库连接资源被消耗光,出现系统宕机等情况,所以尽量避免发生这样的情况。

  • 因此在一般的应用中我们往往希望 SqlSessionFactory 作为一个单例,让它在应用中被共享。所以说 SqlSessionFactory 的最佳作用域是应用作用域。

  • 如果说 SqlSessionFactory 相当于数据库连接池,那么 SqlSession 就相当于一个数据库连接(Connection 对象),你可以在一个事务里面执行多条 SQL,然后通过它的 commit、rollback 等方法,提交或者回滚事务。所以它应该存活在一个业务请求中,处理完整个请求后,应该关闭这条连接,让它归还给 SqlSessionFactory,否则数据库资源就很快被耗费精光,系统就会瘫痪,所以用 try...catch...finally... 语句来保证其正确关闭。

  • 所以 SqlSession 的最佳的作用域是请求或方法作用域。

猜你喜欢

转载自blog.csdn.net/qq_62377885/article/details/133026875
今日推荐