【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
相关推荐
go54631584658 分钟前
使用MATLAB结合EasySpin进行ESR模拟的详细步骤及示例代码
开发语言·数据库·matlab
暴怒的代码3 小时前
云原生监控篇——全链路可观测性与AIOps实战
数据库·sql·mysql
小张-森林人5 小时前
Oracle 字符串分割革命:正则表达式与 Lateral Join 的优雅解法
数据库·oracle·正则表达式
m0_748250937 小时前
SQL Server Management Studio的使用
数据库·oracle·性能优化
车载诊断技术7 小时前
人工智能AI在汽车设计领域的应用探索
数据库·人工智能·网络协议·架构·汽车·是诊断功能配置的核心
没有十八岁7 小时前
云创智城YunCharge 新能源二轮、四轮充电解决方案(云快充、万马爱充、中电联、OCPP1.6J等多个私有单车、汽车充电协议)之新能源充电行业系统说明书
java·数据库·spring·汽车
岁岁岁平安9 小时前
spring注解开发(Spring整合JUnit+MyBatis)(7)
java·spring·junit·log4j·mybatis
爱搞技术的猫猫9 小时前
微店商品详情API接口实战指南:从零实现商品数据自动化获取
大数据·linux·运维·数据库·自动化
若云止水9 小时前
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_init_cycle 函数 - 详解(1)
数据库·nginx·ubuntu
李豆豆喵10 小时前
第38天:安全开发-JavaEE应用&SpringBoot框架&MyBatis注入&Thymeleaf模版注入
java·spring boot·mybatis