【JavaEE进阶】MyBatis 操作数据库(1)

欢迎关注个人主页:逸狼


创造不易,可以点点赞吗

如有错误,欢迎指出~

目录

前⾔

什么是MyBatis?

数据准备

创建对应的实体类UserInfo

配置properties文件

持久层代码Mapper

测试调用

手动生成测试类

将查询内容输出到浏览器里

​编辑

MyBatis的基础操作

打印⽇志

参数传递

增(insert)

返回主键

删(Delete)

改(Update)

查(Select)

起别名

结果映射

开启驼峰命名(推荐)



前⾔

在应⽤分层学习时,我们了解到web应⽤程序⼀般分为三层,即:Controller、Service、Dao. 之前的案例中,请求流程如下:浏览器发起请求,先请求Controller,Controller接收到请求之后,调⽤ Service进⾏业务逻辑处理,Service再调⽤Dao,但是Dao层的数据是Mock的,真实的数据应该从数据库 中读取

对于JDBC来说,整个操作⾮常的繁琐,我们不但要拼接每⼀个参 数,⽽且还要按照模板代码的⽅式,⼀步步的操作数据库,并且在每次操作完,还要⼿动关闭连接 等,⽽所有的这些操作步骤都需要在每个⽅法中重复书写.那有没有⼀种⽅法,可以更简单、更⽅便的 操作数据库呢?

什么是MyBatis?

• MyBatis是⼀款优秀的持久层框架,⽤于简化JDBC的开发。

MyBatis本是Apache的⼀个开源项⽬iBatis,2010年这个项⽬由apache迁移到了googlecode,并 且改名为MyBatis。2013年11⽉迁移到Github.

官⽹:MyBatis中⽂⽹

在上⾯我们提到⼀个词:持久层 • 持久层:指的就是持久化操作的层,通常指数据访问层(dao),是⽤来操作数据库的.

简单来说MyBatis是更简单完成程序和数据库交互的框架也就是更简单的操作和读取数据库⼯具 接下来,我们就通过⼀个⼊⻔程序,让⼤家感受⼀下通过Mybatis如何来操作数据库

数据准备

创建⽤⼾表,并创建对应的实体类UserInfo

先在MySQL中或者navicat中创建一个 名为mybatis_test的mysql数据库.

复制代码
-- 创建数据库 
DROP DATABASE IF EXISTS mybatis_test;
CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;

4-- 使⽤数据数据 
USE mybatis_test;
-- 创建表[⽤⼾表] 
DROP TABLE IF EXISTS user_info;
CREATE TABLE `user_info` (
 `id` INT ( 11 ) NOT NULL AUTO_INCREMENT,
 `username` VARCHAR ( 127 ) NOT NULL,
 `password` VARCHAR ( 127 ) NOT NULL,
 `age` TINYINT ( 4 ) NOT NULL,
 `gender` TINYINT ( 4 ) DEFAULT '0' COMMENT '1-男 2-⼥ 0-默认',
 `phone` VARCHAR ( 15 ) DEFAULT NULL,
 `delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',
 `create_time` DATETIME DEFAULT now(),
 `update_time` DATETIME DEFAULT now() ON UPDATE now(),
 PRIMARY KEY ( `id` ) 
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4; 
-- 添加⽤⼾信息 
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'admin', 'admin', 18, 1, '18612340001' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );

创建对应的实体类UserInfo

实体类的属性名与表中的字段名⼀⼀对应

复制代码
package com.example.demo.model;

import lombok.Data;

import java.util.Date;

@Data
//创建mybatis_test数据库对应的类
public class UserInfo {

    private Integer id;
    private String username;
    private String password;
    private Integer age;
    private Integer gender;
    private String phone;
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
}

配置properties文件

配置数据库连接字符串 Mybatis中要连接数据库,需要数据库相关参数配置 • MySQL驱动类 • 登录名 • 密码 • 数据库连接字符串

复制代码
#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mybatis_test?
characterEncoding=utf8&useSSL=false
#连接数据库的⽤⼾名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password="111111"

注意事项: 如果使⽤MySQL是5.x之前的使⽤的是"com.mysql.jdbc.Driver",如果是⼤于5.x使⽤的 是"com.mysql.cj.jdbc.Driver".

持久层代码Mapper

复制代码
package com.example.demo.mapper;


import com.example.demo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;
@Mapper//将对象交给spring管理
public interface UserInfoMapper {
    //查询所有用户信息

    @Select("select * from user_info")
    List<UserInfo> selectAll();

}

Mybatis的持久层接⼝规范⼀般都叫XxxMapper @Mapper注解:表⽰是MyBatis中的Mapper接⼝ • 程序运⾏时,框架会⾃动⽣成接⼝的实现类对象(代理对象),并给交Spring的IOC容器管理 • @Select注解:代表的就是select查询,也就是注解对应⽅法的具体实现内容.

测试调用

在创建出来的SpringBoot⼯程中,在src下的test⽬录下,已经⾃动帮我们创建好了测试类,我们可以 直接使⽤这个测试类来进⾏测试.

复制代码
package com.example.demo;

import com.example.demo.mapper.UserInfoMapper;
import com.example.demo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class Demo6ApplicationTests {

	@Autowired
	private UserInfoMapper userInfoMapper;

	@Test
	void contextLoads() {
//		System.out.println(userInfoMapper.selectAll().toString());//调用查询方法
		
		//使用lambda表达式

        userInfoMapper.selectAll().forEach(x -> System.out.println(x));

		//List<UserInfo> userInfos = userInfoMapper.selectAll();
		//userInfos.forEach(x -> System.out.println(x));
		
//		List<UserInfo> userInfos = userInfoMapper.selectAll();
//		for(UserInfo userInfo : userInfos){
//			System.out.println(userInfo.toString());
//		}
	}
}

测试类上添加了注解@SpringBootTest,该测试类在运⾏时,就会⾃动加载Spring的运⾏环境. 我们通过@Autowired这个注解,注⼊我们要测试的类,就可以开始进⾏测试了

手动生成测试类

使⽤Idea⾃动⽣成测试类 除此之外,也可以使⽤Idea⾃动⽣成测试类 1. 在需要测试的Mapper接⼝中,右键->Generate->Test

复制代码
package com.example.demo.mapper;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class UserInfoMapperTest {

    @BeforeEach
    void setUp() {
        System.out.println("BeforeEach");
    }

    @AfterEach
    void tearDown() {
        System.out.println("AfterEach");
    }

    @Test
    void selectAll() {
        System.out.println("selectAll111");
    }

    @Test
    void SelectAll222() {
        System.out.println("SelectAll222");
    }
}

将查询内容输出到浏览器里

UserController类

复制代码
package com.example.demo.Controller;

import com.example.demo.Service.UserService;
import com.example.demo.model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping("/v1")
    public List<UserInfo> v1(){
        return userService.selectUserList();
    }

}

UserSevice类

复制代码
package com.example.demo.Service;

import com.example.demo.mapper.UserInfoMapper;
import com.example.demo.model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserService {

    @Autowired
    private UserInfoMapper userInfoMapper;
    public List<UserInfo> selectUserList() {
        return userInfoMapper.selectAll();
    }
}

MyBatis的基础操作

上⾯我们学习了Mybatis的查询操作,接下来我们学习MyBatis的增,删,改操作

在学习这些操作之前,我们先来学习MyBatis⽇志打印

打印⽇志

在Mybatis当中我们可以借助⽇志,查看到sql语句的执⾏、执⾏传递的参数以及执⾏结果

在配置⽂件中进⾏配置

复制代码
#指定mybatis输出⽇志的位置, 输出控制台 
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

重新运行测试

①:查询语句 ②:传递参数及类型 ③:SQL执⾏结果

参数传递

需求:查找id=4的⽤⼾,对应的SQL就是:select*fromuser_infowhereid=4

复制代码
    @Select("select * from user_info where id = 4;")
    List<UserInfo> selectById();

但是这样就写死了,所以SQL语句中的id值不能写成固定数值,需要变为动态的数值 解决⽅案:在queryById⽅法中添加⼀个参数(id),将⽅法中的参数,传给SQL语句 使⽤#{} 的⽅式获取⽅法中的参数

修改后

复制代码
    @Select("select * from user_info where id = #{id};")
    List<UserInfo> selectById(Integer id);

如果mapper接⼝⽅法形参只有⼀个普通类型的参数,#{...}⾥⾯的属性名可以随便写,如:#{id}、# {value}。建议和参数名保持⼀致

复制代码
    @Test
    void selectById(){
        userInfoMapper.selectById(3).forEach(x -> System.out.println(x));
    }

也可以通过 @Param ,设置参数的别名,如果使⽤ @Param 设置别名,#{...}⾥⾯的属性名必须和 @Param 设置的⼀样

复制代码
@Select("select username, `password`, age, gender, phone from user_info where 
id= #{userid} ")
UserInfo queryById(@Param("userid") Integer id);

MyBatis会根据⽅法的返回结果进⾏赋值.

  1. ⽅法⽤对象UserInfo接收返回结果,MySQL查询出来数据为⼀条,就会⾃动赋值给对象.
  2. ⽅法⽤List接收返回结果 ,MySQL查询出来数据为⼀条或多条时,也会⾃动赋值给List. 但如果MySQL查询返回多条,但是⽅法使⽤UserInfo接收,MyBatis执⾏就会报错.

增(insert)

接口方法

复制代码
    @Insert("insert into user_info (username, `password`, age, gender, phone) values(#{username}, #{password}, #{age}, #{gender}, #{phone})")
    Integer insert(UserInfo userInfo);

测试

复制代码
    @Test
    void insert(){
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("zhao");
        userInfo.setPassword("111");
        userInfo.setAge(12);
        userInfo.setGender(1);
        userInfo.setPhone("1008611");
        userInfoMapper.insert(userInfo);
    }

如果设置了 @Param 属性,#{...}需要使⽤参数.属性来获取

复制代码
@Insert("insert into user_info (username, `password`, age, gender, phone) 
values (#{userInfo.username},#{userInfo.password},#{userInfo.age},#
{userInfo.gender},#{userInfo.phone})")
Integer insert(@Param("userInfo") UserInfo userInfo);

如果直接写属性,会有下面报错

返回主键

Insert语句默认返回的是受影响的⾏数 但有些情况下,数据插⼊之后,还需要有后续的关联操作,需要获取到新插⼊数据的id ⽐如订单系统 当我们下完订单之后,需要通知物流系统,库存系统,结算系统等,这时候就需要拿到订单ID 如果想要拿到⾃增id,需要在Mapper接⼝的⽅法上添加⼀个Options的注解

复制代码
    @Options(useGeneratedKeys = true, keyProperty = "id")
    @Insert("insert into user_info (username, `password`, age, gender, phone) values(#{username}, #{password}, #{age}, #{gender}, #{phone})")
    Integer insert(@Param("userInfo") UserInfo userInfo);
  1. useGeneratedKeys:这会令MyBatis使⽤JDBC的getGeneratedKeys⽅法来取出由数据库内 部⽣成的主键(⽐如:像MySQL和SQLServer这样的关系型数据库管理系统的⾃动递增字 段),默认值:false
  2. keyProperty:指定能够唯⼀识别对象的属性,MyBatis会使⽤getGeneratedKeys的返回值或 insert语句的selectKey⼦元素设置它的值,默认值:未设置(unset)

测试

复制代码
    //拿到自增id
    @Test
    void testInsert() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("zhaolll");
        userInfo.setPassword("111");
        userInfo.setAge(12);
        userInfo.setGender(1);
        userInfo.setPhone("1008611");
        Integer count = userInfoMapper.insert(userInfo);
        System.out.println("增加的数据条数: " + count + " id: " + userInfo.getId());
    }

结果

删(Delete)

接口方法

复制代码
    @Delete("Delete from user_info where id = #{id}")
    Integer delete(Integer id);

测试

复制代码
    @Test
    void delete() {
        System.out.println(userInfoMapper.delete(15));
    }

改(Update)

接口方法

复制代码
    @Update("update user_info set username = #{username} where id = #{id}")
    Integer update(UserInfo userInfo);

     @Update("update user_info set username = #{username} where id = #{id}")
    Integer update1(String username, Integer id);

测试

复制代码
    @Test
    void update() {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(18);
        userInfo.setUsername("zzzz");
        System.out.println(userInfoMapper.update(userInfo));
    }

    @Test
    void testUpdate() {
        System.out.println(userInfoMapper.update1("haha",1));
    }

查(Select)

我们在上⾯查询时发现,有⼏个字段是没有赋值的,只有Java对象属性和数据库字段⼀模⼀样时,才会进 ⾏赋值

原因分析: 当⾃动映射查询结果时,MyBatis会获取结果中返回的列名并在Java类中查找相同名字的属性(忽略 ⼤⼩写)。这意味着如果发现了ID列和id属性,MyBatis会将列ID的值赋给id属性

解决办法: 1. 起别名 2. 结果映射 3. 开启驼峰命名

起别名

在SQL语句中,给列名起别名,保持别名和实体类属性名⼀样

复制代码
     @Select("select id, username, `password`, age, gender, phone, delete_flag as deleteFlag, create_time as createTime, update_time as updateTime from user_info")
    List<UserInfo> select1();

结果映射

复制代码
     //;结果映射
     @Select("select id, username, `password`, age, gender, phone, delete_flag, \n" +
             "create_time, update_time from user_info")
     @Results({
             @Result(column = "delete_flag",property = "deleteFlag"),
             @Result(column = "create_time",property = "createTime"),
             @Result(column = "update_time",property = "updateTime")
     })
    List<UserInfo> select2();

如果其他SQL,也希望可以复⽤这个映射关系,可以给这个Results定义⼀个名称id

在其他sql使用注解@ResultMap

复制代码
     @Select("select id, username, `password`, age, gender, phone, delete_flag, \n" +
             "create_time, update_time from user_info")
     @Results(id = "resultMap",value = {
             @Result(column = "delete_flag",property = "deleteFlag"),
             @Result(column = "create_time",property = "createTime"),
             @Result(column = "update_time",property = "updateTime")
     })
    List<UserInfo> select2();

    @Select("select * from user_info where id = #{id};")
    @ResultMap("resultMap")
    List<UserInfo> selectById(@Param("id") Integer userId);

开启驼峰命名(推荐)

通常数据库列使⽤蛇形命名法进⾏命名(下划线分割各个单词),⽽Java属性⼀般遵循驼峰命名法约定. 为了在这两种命名⽅式之间启⽤⾃动映射,只需要将mapUnderscoreToCamelCase 设置为true。Java代码不做任何处理

proporties文件配置

复制代码
#配置驼峰⾃动转换
mybatis.configuration.map-underscore-to-camel-case=true 
  • 驼峰命名规则:abc_xyz=>abcXyz
  • 表中字段名:abc_xyz • 类中属性名:abcXyz
相关推荐
TDengine (老段)6 分钟前
TDengine 时间函数 TODAY() 用户手册
大数据·数据库·物联网·oracle·时序数据库·tdengine·涛思数据
码界奇点15 分钟前
KingbaseES一体化架构与多层防护体系如何保障企业级数据库的持续稳定与弹性扩展
数据库·架构·可用性测试
悟乙己38 分钟前
数据科学家如何更好地展示自己的能力
大数据·数据库·数据科学家
皆过客,揽星河1 小时前
mysql进阶语法(视图)
数据库·sql·mysql·mysql基础语法·mysql进阶语法·视图创建修改删除
tuokuac2 小时前
Redis 的相关文件作用
数据库·redis·缓存
鹧鸪云光伏与储能软件开发3 小时前
投资储能项目能赚多少钱?小程序帮你测算
运维·数据库·小程序·光伏·光伏设计软件·光伏设计
2301_779503764 小时前
MySQL主从同步--主从复制进阶
数据库·mysql
beijingliushao4 小时前
58-正则表达式
数据库·python·mysql·正则表达式
诗句藏于尽头5 小时前
DJANGO后端服务启动报错及解决
数据库·笔记·django
手握风云-5 小时前
MySQL数据库精研之旅第十五期:索引的 “潜规则”(下)
数据库