当前位置: 首页 > article >正文

【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

    http://www.kler.cn/a/563325.html

    相关文章:

  1. Mysql疑难报错排查 - Field ‘XXX‘ doesn‘t have a default value
  2. MySQL--索引的优化--LIKE模糊查询
  3. Java IO 和 NIO 的基本概念和 API
  4. 渗透测试(WAF过滤information_schema库的绕过,sqllib-46关,海洋cms9版本的注入)
  5. SOME/IP-SD -- 协议英文原文讲解4
  6. 【leetcode hot 100 11】移动零
  7. FTP出现“打开 FTP 服务器上的文件夹时发生错误。请检查是否有权限访问该文件夹。”如何处理?
  8. SpringBoot 2 后端通用开发模板搭建(异常处理,请求响应)
  9. DeepSeek “源神”启动!「GitHub 热点速览」
  10. Harbor服务需要crt证书,而下载是nginx的证书pem,应该怎么处理
  11. uniapp-X 对象动态取值
  12. [Web 安全] PHP 反序列化漏洞 —— PHP 序列化 反序列化
  13. 半导体芯片制造中 W CVD(钨化学气相沉积)
  14. Docker启动ES容器打包本地镜像
  15. mmdetection框架下使用yolov3训练Seaships数据集
  16. 安卓工控平板电脑在环境监测设备中的运用
  17. 前端实现rsa加密功能
  18. 26.贪心算法4
  19. 第二十二天 学习HarmonyOS的分布式软总线技术,了解跨设备通信的原理
  20. 【原创工具】同文件夹PDF文件合并 By怜渠客