20201224——Mybatis(上)

简介

mybatis是一个持久层框架,支持定制化的sql,存储过程以及高级映射,避免了所有jdbc代码和手动参数集以及获取结果集,mybatis可以使用简单的xml或者注解来配置和映射原生类型,接口和java中的pojo

持久层

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

第一个mybatis程序

环境搭建

在navicat中创建数据库

CREATE DATABASE `mybatismmz`;

创建表

CREATE TABLE user(
	id INT(20) not null PRIMARY KEY,
	name VARCHAR(30) DEFAULT NULL,
	pwd VARCHAR(30) DEFAULT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;

别忘符号的关系

插入数据

INSERT INTO user(id,name,pwd) VALUES
(1,'mmz','123'),
(2,'mmz1','213'),
(3,'mmz2','321')

创建一个普通的maven项目,是父工程。导入依赖创建子工程

导入父工程依赖pom.xml

<?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.mmz</groupId>
    <artifactId>MmzMybatisLearning</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!--导入依赖-->
    <dependencies>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>
    </dependencies>
</project>

创建一个子module

在子module中配置mybatis的

配置文件mybatis-config.xml

<?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="mysql">
        <environment id="mysql">
            <!--            事务类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!--   配置数据源(连接池)         -->
            <dataSource type="POOLED">
                <!--                配置数据库的四个基本信息-->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"></property>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatismmz?serverTimezone=UTC&amp;useUnicode=true&amp;characterEncoding=utf-8"></property>
                <property name="username" value="root"></property>
                <property name="password" value="password"></property>
            </dataSource>
        </environment>
    </environments>

    <!--如果是用注解来配置的话,应该使用class属性指定被注解的dao全限定类名-->
    <mappers>

    </mappers>

</configuration>

编写mybatis工具类

每个基于mybatis的应用都是以一个sqlsessionfactory的实例为核心的,sqlsessionfactory的实例可以通过sqlsessionfactorybuilder获得。这个builder可以通过xml配置文件或者一个预定先定制的Configuration的实例构建出来。
在这里插入图片描述

可以从sqlsessionfactory中获取sqlsession,因为sqlsession里面包含了所有数据库执行sql命令所需要的方法,你可以通过sqlsession实例来直接执行已经映射的sql语句

在这里插入图片描述

编写实体类

package com.mmz.pojo;

/**
 * @Classname User
 * @Description TODO
 * @Date 2020/12/24 21:57
 * @Created by mmz
 */
// 实体类
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;
    }
}

编写测试类

package com.mmz.dao;

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

import java.util.List;

/**
 * @Classname UserDaoTest
 * @Description TODO
 * @Date 2020/12/24 22:18
 * @Created by mmz
 */
public class UserDaoTest {
    @Test
    public void test(){
        // 创建sqlsession对象
        SqlSession sqlsession = MybatisUtils.getSqlsession();

        // 得到mapper 方式一
        UserDao mapper = sqlsession.getMapper(UserDao.class);

        // 方式二

        List<User> userList = mapper.getUserList();
        for (User user : userList){
            System.out.println(user);
        }

        // 关闭sqlsession
        sqlsession.close();
    }
}

编写UserDao的mapper文件

<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.mmz.dao.UserDao">
    <!--    配置查询所有-->
    <select id="getUserList" resultType="com.mmz.pojo.User">
        select * from user;
    </select>
</mapper>

小结 比较mybatis和传统的jdbc

首先,我们获得一个叫sqlsession的东西,sqlsession可以根据我们写的userdao这个类对象来获得相应的mapper对象,然后通过这个对象来调用方法。

UserDao mapper = sqlsession.getMapper(UserDao.class);

当然sqlsession是如何知道这个mapper,需要在mybatis-config.xml中配置

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

最后我们得到这个mapper,调用userdao接口中的方法。那方法之所以能执行sql语句,是因为mapper.xml中已经写好了sql语句。mapper.xml就是写了sql语句,与绑定的userdao

<mapper namespace="com.mmz.dao.UserDao">
    <!--    配置查询所有-->
    <select id="getUserList" resultType="com.mmz.pojo.User">
        select * from user;
    </select>
</mapper>

基础CRUD

namespace 命名空间

namespace中的包名和Dao/Mapper接口名称一致。

select

select标签相当于查询语句
id就是对应的namespace中的方法
resultType sql语句中执行的返回值
还可能有paramterType 参数类型

根据用户id查找用户

当然我们只需要增加userdao中接口的方法

    // 根据id查询用户
    User getUserById(int id);

同样的,我们需要在usermapper.xml中增加select标签,添加查询的sql语句

    <select id="getUserById" resultType="com.mmz.pojo.User" parameterType="int">
        select * from user where id = #{id}
    </select>

最后增加test测试方法

@Test
    public void testFindUserById(){
        SqlSession sqlsession = MybatisUtils.getSqlsession();

        // 得到mapper 方式一
        UserDao mapper = sqlsession.getMapper(UserDao.class);

        User userById = mapper.getUserById(1);

        System.out.println(userById);

    }

在这里插入图片描述

增加一个用户

xml配置文件中添加

    <!--对象中的属性可以直接取出来-->
    <insert id="addUser" parameterType="com.mmz.pojo.User" >
        insert into user (id, name, pwd) values (#{id},#{name},#{pwd});
    </insert>

测试代码

// 增删改需要提交事务
    @Test
    public void testAddUser(){
        SqlSession sqlsession = MybatisUtils.getSqlsession();

        UserDao mapper = sqlsession.getMapper(UserDao.class);

        User user = new User(4,"duoduo","123");
        int i = mapper.addUser(user);

        System.out.println(i);

        sqlsession.commit();
        sqlsession.close();
    }

记住必须要记住,除了查询之外,增删改数据库,需要提交事务。

修改更新

xml配置文件

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

测试类代码

// 修改更新User
    @Test
    public void testUpdateUser(){
        SqlSession sqlsession = MybatisUtils.getSqlsession();

        UserDao mapper = sqlsession.getMapper(UserDao.class);

        User user = new User(4,"duoduo123","123");
        int i = mapper.updateUser(user);

        System.out.println(i);

        sqlsession.commit();
        sqlsession.close();
    }

在这里插入图片描述

删除用户

xml配置文件

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

测试类

 // 删除修改User
    @Test
    public void testDeleteUser(){
        SqlSession sqlsession = MybatisUtils.getSqlsession();

        UserDao mapper = sqlsession.getMapper(UserDao.class);

        int i = mapper.deleteUser(4);

        System.out.println(i);

        sqlsession.commit();
        sqlsession.close();
    }

在这里插入图片描述

万能map

假设,我们的实体类,或者数据库中的表,字段或者参数过多,我们应当会考虑Map

xml配置文件

<!--传递map中的key,这样解决了如果User类有过多属性-->
    <insert id="addUser2" parameterType="map" >
        insert into user (id, name, pwd) values (#{userid},#{username},#{userpwd});
    </insert>
 // 增删改需要提交事务
    @Test
    public void testAddUser2(){
        SqlSession sqlsession = MybatisUtils.getSqlsession();

        UserDao mapper = sqlsession.getMapper(UserDao.class);

        Map<String,Object> map = new HashMap<String, Object>();

        map.put("userid",5);
        map.put("username","xiaoqi");
        map.put("userpwd","jinmao");
        int i = mapper.addUser2(map);

        System.out.println(i);

        sqlsession.commit();
        sqlsession.close();
    }

Map传递参数,直接在sql中取出key即可
对象传递参数,直接在sql中取出对象的属性即可,
只有一个基本类型参数的情况下, 可以默认在xml配置文件中不写
多个参数如果用到了对象,需要写上全限定类名
当然还有注解的方式

模糊查询

1.java代码执行的时候,传递通配符%

        List<User> m = mapper.getUserLike("%m%");

这样不会产生sql注入,需要在java方法里面去写

2.在sql拼接中使用通配符,这样会产生sql注入

select * from user where name like “%”#{value}%;

mybatis的配置解析

核心配置文件mybatis-config.xml

官方建议使用这个名字

环境配置environments

mybatis可以配置多种环境配置,

<environments default="mysql">
        <environment id="mysql">
            <!--            事务类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!--   配置数据源(连接池)         -->
            <dataSource type="POOLED">
                <!--                配置数据库的四个基本信息-->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"></property>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatismmz?serverTimezone=UTC&amp;useUnicode=true&amp;characterEncoding=utf-8"></property>
                <property name="username" value="root"></property>
                <property name="password" value="password"></property>
            </dataSource>
        </environment>
    </environments>

可以在这个environments属性中的default属性中设置选择的环境配置

事务管理器

<transactionManager type="JDBC"></transactionManager>

在mybatis有两种类型的事务管理器JDBC/MANAGED

数据源

连接数据库
dbcp cp30 druid
有三种类型内建的数据库 UNPOOLED POOLED JNDI

UNPOOLED

这个数据源的实现只是每次请求的时候打开和关闭连接,虽然有点慢。但是对于在数据库连接可用性方面没有太高的要求的简单程序,是一个很好的选择。

属性properties

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

编写db.propeties的配置文件

dirver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatismmz?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
username=root
password=password

在核心配置文件中引入

 <properties resource="db.properties"></properties>
    <environments default="mysql">
        <environment id="mysql">
            <!--            事务类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!--   配置数据源(连接池)         -->
            <dataSource type="POOLED">
                <!--                配置数据库的四个基本信息-->
                <property name="driver" value="${driver}"></property>
                <property name="url" value="${url}"></property>
                <property name="username" value="${username}"></property>
                <property name="password" value="${password}"></property>
            </dataSource>
        </environment>
    </environments>

优先使用外部配置文件

类型别名

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

第一种方式自己配置

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

第二种指定包名

在每一个包中的javabean,在没有注解的情况下面,会使用Bean的首字母小写的非限定类名来作为他的别名,若有注解,为注解的值@Alias(“author”)

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

总结

实体类少,建议使用第一种
实体类多,建议使用第二种
第一种可以diy,第二种无法自定义
当然还有一些默认别名,基本类和包装类

设置settings

这是mybatis中及其重要的调整设置,他们会改变mybatis的运行时的行为

映射器mappers

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

第一种使用资源路径

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

第二种使用class文件绑定注册

注意接口和mapper配置文件必须同名,接口和配置文件必须在同一个包下面

第三种使用package

        <package name="com.mmz.dao"/>

使用扫描包注入的时候,与第二种一样,mapper配置文件与接口必须同名,接口和配置文件必须在同一个包下面

生命周期和作用域

sqlsessionfactorybuilder

一旦创建sqlsessionfactory,就不需要他了
局部变量

sqlsessionfactory

说白了就是数据库连接池
一旦被创建就应该在运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例
单例模式

sqlsession

相当于数据库连接的一个线程请求
用完之后关闭,否则资源被占用

ResultMap结果集

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

现在我开了一个新的module,mybatis-03,把密码的pwd改成了password
进行查询,发现password=null
在这里插入图片描述

解决方案

在sql中起别名
在这里插入图片描述

我们所谓的resultMap

结果集映射resultMap

 <resultMap id="UserMap" type="User">
        <!--colunm是数据库中的字段,property实体类中的属性-->
        <result column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="pwd" property="password"/>
    </resultMap>

    <select id="getUserById" resultMap="UserMap" parameterType="int">
        select * from user where id = #{id};
    </select>

要在UserDao.xml中写好resultMap标签,然后在下面的sql查询中,设置返回结果为ResultMap,也就是我们定义好的id
在这里插入图片描述

日志

日志工厂

如果一个数据库操作出现了异常,我们需要排错,日志就是最好的助手。
曾经:sout,debug
现在:日志工厂

具体使用哪个日志工厂,是mybatis可选择

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

在这里插入图片描述

Log4j

先导入log4j的包
log4ja是apache的一个开源项目,通过使用log4j,我们可以控制日志信息输送的目的是控制台,文件,gui组件
我们可以通过配置文件来灵活配置,不需要修改应用代码

配置文件log4j.properties

# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE            debug   info   warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE

# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE

# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=./log/mmz.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

在这里插入图片描述

分页

为什么要分页?
减少数据的处理量

使用limit分页

sql中的limit分页

select * from user limit startIndex,pageSize;
select * from user limit 0,2;

在这里插入图片描述

使用mybatis实现分页

接口

 // 分页
    List<User> getUserByLimit(Map<String,Integer> map);

配置xml文件

 <!--分页实现-->
    <select id="getUserByLimit" parameterType="map" resultMap="UserMap">
        select * from user limit #{startIndex},#{pageSize}
    </select>

测试类

@Test
    public void testLimit(){
        SqlSession sqlsession = MybatisUtils.getSqlsession();
        UserDao mapper = sqlsession.getMapper(UserDao.class);
        HashMap<String, Integer> hashMap = new HashMap<String, Integer>();
        hashMap.put("startIndex",0);
        hashMap.put("pageSize",2);
        List<User> userByLimit = mapper.getUserByLimit(hashMap);
        for (User user : userByLimit) {
            System.out.println(user);
        }

        sqlsession.close();
    }

注解开发

接口

package com.mmz.dao;

import com.mmz.pojo.User;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * @Classname UserMapper
 * @Description TODO
 * @Date 2021/1/2 7:11
 * @Created by mmz
 */
public interface UserMapper {

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

配置文件

    <!--绑定接口-->
    <mappers>
        <mapper class="com.mmz.dao.UserMapper"></mapper>
    </mappers>

测试类

package com.mmz.dao;

import com.mmz.pojo.User;
import com.mmz.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.junit.Test;
import sun.rmi.runtime.Log;

import java.util.HashMap;
import java.util.List;

/**
 * @Classname UserDaoTest
 * @Description TODO
 * @Date 2020/12/26 16:47
 * @Created by mmz
 */
public class UserDaoTest {

    static Logger logger = Logger.getLogger(UserDaoTest.class);

    @Test
    public void getUserList(){
        SqlSession sqlsession = MybatisUtils.getSqlsession();

        UserDao mapper = sqlsession.getMapper(UserDao.class);

        User userList = mapper.getUserById(1);

        System.out.println(userList);
        sqlsession.close();
    }

    @Test
    public void testLog4j(){
        logger.info("info 进入了test");
        logger.debug("info 进入了test");
        logger.error("info 进入了test");
    }

    @Test
    public void testLimit(){
        SqlSession sqlsession = MybatisUtils.getSqlsession();
        UserDao mapper = sqlsession.getMapper(UserDao.class);
        HashMap<String, Integer> hashMap = new HashMap<String, Integer>();
        hashMap.put("startIndex",0);
        hashMap.put("pageSize",2);
        List<User> userByLimit = mapper.getUserByLimit(hashMap);
        for (User user : userByLimit) {
            System.out.println(user);
        }

        sqlsession.close();
    }

}

执行过程

Resources获取加载全局配置文件
实例化SqlSessionBuilder构造器
解析配置文件流XMLConfigBuilder
Configuration所有的配置文件
SqlSessionFactory实例化
transaction事务管理器
executor执行器
创建sqlsession
实现crud
查看是否执行成功,可能回滚
执行成功,提交事务
关闭

注解crud

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

编写mapper接口

package com.mmz.dao;

import com.mmz.pojo.User;
import org.apache.ibatis.annotations.*;

import java.util.List;

/**
 * @Classname UserMapper
 * @Description TODO
 * @Date 2021/1/2 7:11
 * @Created by mmz
 */
public interface UserMapper {

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

    // 方法存在多个参数,所有的参数前面必须加上@param注解
    @Select("select * from user where id = #{id}")
    User getUserById(@Param("id") int id);

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

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

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

测试类测试

package com.mmz.usermapper;

import com.mmz.dao.UserMapper;
import com.mmz.pojo.User;
import com.mmz.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

/**
 * @Classname testUserMapper
 * @Description TODO
 * @Date 2021/1/2 7:13
 * @Created by mmz
 */
public class testUserMapper {
    @Test
    public void test(){
        SqlSession sqlsession = MybatisUtils.getSqlsession();
        UserMapper mapper = sqlsession.getMapper(UserMapper.class);

        List<User> users = mapper.getUsers();
        for (User user : users) {
            System.out.println(user);
        }
        sqlsession.close();
    }

    @Test
    public void testById(){
        SqlSession sqlsession = MybatisUtils.getSqlsession();
        UserMapper mapper = sqlsession.getMapper(UserMapper.class);

        User user = mapper.getUserById(1);
        System.out.println(user);
        sqlsession.close();
    }

    @Test
    public void testAddUser(){
        SqlSession sqlsession = MybatisUtils.getSqlsession();
        UserMapper mapper = sqlsession.getMapper(UserMapper.class);

        User user = new User(6,"hello","231231");
        int i = mapper.addUser(user);
        System.out.println(i);
        sqlsession.close();
    }

    @Test
    public void testUpdateUser(){
        SqlSession sqlsession = MybatisUtils.getSqlsession();
        UserMapper mapper = sqlsession.getMapper(UserMapper.class);

        User user = new User(6,"xixi","231231");
        mapper.updateUser(user);
        sqlsession.close();
    }

    @Test
    public void testDeleteUser(){
        SqlSession sqlsession = MybatisUtils.getSqlsession();
        UserMapper mapper = sqlsession.getMapper(UserMapper.class);

        int i = mapper.deleteUser(5);
        sqlsession.close();
    }
}

关于@param注解

基本类型的参数或者String类型,需要加上
引用类型不需要加
如果只有一个基本类型,可以忽略,但是建议大家都加上

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值