JavaWeb笔记——Mybatis环境、增删查改


黑马程序员2023年javaweb网课笔记,自用


tip1:Springboot的单元测试方式

  1. 在test下有一个springboot自带的测试文件
    在这里插入图片描述
  2. 函数带上@Test注释,可以测试函数,测试时会自动带上工程环境
    在这里插入图片描述

tip2:Java HotSpot™ 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended

虽然csdn给出的解决方案是如右链接,解决方案,但本人设置后没能解决这个warning,由于没发现运行带来的问题,暂时保留


tip3 :idea配置sql语句提示

  1. 选中sql语句,如下操作:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  2. 如果成功,sql语句中的关键字会显色;如果表名称爆红,则是idea没连上对应的mysql数据库,检查一下相关问题。
    在这里插入图片描述

tip4 :Cannot invoke “com.liquor.mybatis_01.maper.EmpMapper.delete(java.lang.Integer)” because “this.empMapper” is null

  1. 错误:尝试调用一个空对象的方法。
  2. 原因:测试类中创建的变量没使用依赖注入,注意,每一个变量都需要单独写一个依赖注入注释
    在这里插入图片描述

tip5 :不同springboot版本/单独使用mybatis对参数名称的附加说明

在这里插入图片描述


一、基础

1.1 概论

  1. MyBatis是一款优秀的持久层框架,用于简化JDBC的开发。

1.2 入门程序

流程:

  1. 准备工作(创建springboot工程、数据库表user、实体类User)
  2. 引入Mybatis的相关依赖,配置Mybatis(数据库连接信息)
  3. 编写SQL语句(注解/XML)
  1. 创建springboot的Moudle,勾选mybatis需要的框架和支持sql的文件
    在这里插入图片描述
  2. 上一步勾好后,maven自动生成的依赖文件pom.xml中引入的mybatis依赖
    <dependencies>
        <!--mybatis的起步依赖-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>3.0.2</version>
        </dependency>
        <!--mysql的驱动包,如果是mysql-connector-java则是上个版本的驱动包-->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!--springboot单元测试依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter-test</artifactId>
            <version>3.0.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
  1. 连接mysql,创建数据库表user
    在这里插入图片描述

  2. 在java->com.xxx->pojo下建立实体类User,和数据库字段名称一致,自生成get、set和toString:
    其中:
    1)int->Integer
    2)varchar(n)->String
    3)tinyint unsigned->Short
    在这里插入图片描述

  3. 在resources下的application.properties中配置mybatis连接mysql的信息,数据库连接的url,把mybatis改成自己的数据库名称

# 驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 数据库连接的url
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis
# 用户名
spring.datasource.username=root
# 密码
spring.datasource.password=12345678

在这里插入图片描述

  1. 在java->com.xxx->mapper下,建立接口UserMapper,使用注释@Mapper,查询语句使用注释@Select(“查询sql语句”)此处注意是注释,不需要分号
@Mapper//运行时自动生成接口的实现类对象,交给IOC容器管理
public interface UserMapper {
    @Select("select * from user") // mysql的语句
    public List<User> list();  //列表存储查询结果
}
  1. 测试文件代码:
@SpringBootTest//整合单元测试的注解
class Mybatis01ApplicationTests {

    @Autowired//之前使用@Mapper管理,现在可以直接自动注入
    private UserMapper userMapper;

    @Test
    public void testListUser() {
        List<User> userList = userMapper.list();//调用函数
        userList.stream().forEach(user->{
            System.out.println(user.toString());
        });
        
    }
}
  1. 测试结果:
    在这里插入图片描述

1.3 JDBC(仅了解,和mybatis对比)

  1. JDBC: ( Java DataBase Connectivity ),就是使用Java语言操作关系型数据库的一套API
  2. JDBC程序示例:繁琐臃肿,频繁开关流浪费资源
    @Test
    public void testJdbc() throws Exception {
        //1. 注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");

        //2. 获取连接对象
        String url = "jdbc:mysql://localhost:3306/db01";
        String username = "root";
        String password = "123";
        Connection connection = DriverManager.getConnection(url, username, password);

        //3. 获取执行SQL的对象Statement,执行SQL,返回结果
        String sql = "select * from user";
        Statement statement = connection.createStatement();
        ResultSet resultSet = statement.executeQuery(sql);

        //4. 封装结果数据
        List<User> userList = new ArrayList<>();
        while (resultSet.next()){
            int id = resultSet.getInt("id");
            String name = resultSet.getString("name");
            short age = resultSet.getShort("age");
            short gender = resultSet.getShort("gender");
            String phone = resultSet.getString("phone");

            User user = new User(id,name,age,gender,phone);
            userList.add(user);
        }
        //显示结果
        System.out.println(userList);

        //5. 释放资源
        statement.close();
        connection.close();
    }


1.4 数据库连接池

  1. 数据库连接池是个容器,负责分配、管理数据库连接(Connection)。
    1)资源重用,提高响应速度:允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。
    2)避免数据库连接遗漏:释放空闲时间超过最大空闲时间的连接
  2. 数据库接口:DataSource
    1)Druid德鲁伊:阿里巴巴开源的数据库连接池项目
    2)Hikari(springboot默认)
    在这里插入图片描述
  3. 切换德鲁伊:引入依赖

德鲁伊官网:https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter

<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>druid-spring-boot-starter</artifactId>
	<version>1.2.8</version>
</dependency>

1.5 lombok工具包——简化实体类

  1. Lombok是一个实用的Java类库,能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,并可以自动化生成日志变量,简化java开发、提高效率。
  2. 引入依赖:
<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
</dependency>
  1. 注解:@Data中不包含无参和全参的构造,一般在实体类之前声明以下三个注释:
@Data//=@Getter + @Setter + @ToString + @EqualsAndHashCode
@NoArgsConstructor//无参构造
@AllArgsConstructor//全参构造
public class User {
    private Integer id;
    private String name;
    private Short age;
    private Short gender;
    private String phone;
}

在这里插入图片描述


二、Mybatis基础操作

2.1 环境

  1. 引入对应的起步依赖(mybatis、mysql驱动、lombok)
  2. application.properties中引入数据库连接信息
  3. 准备数据库表 emp
  4. 创建对应的实体类 Emp(实体类属性采用驼峰命名,使用lombok的注释)
  5. 准备Mapper接口 EmpMapper,使用注释@Mapper

2.2 删除操作

  1. 在EmpMapper接口中写接口函数使用注释写sql语句,其中占位符使用#{}表示,从函数中传递参数,两者名称保持一致
  2. 代码:此处返回的int数值是被该语句影响的数据条数
    //删除ID大于14的数据
    @Delete("delete from tb_emp where id >#{id}")
    public int delete(Integer id);
  1. 在测试文件中,增加EmpMapper类变量,用依赖注入注释;在@Test下写测试函数:
    @Autowired
    private EmpMapper empMapper;
    @Test
    public void testDelete(){
        int deleteResult = empMapper.delete(14);
        System.out.println(deleteResult);
    }
  1. 结果为2,因为大于14的有两条
    在这里插入图片描述
  2. 但一般不需要这个返回值,设置为void即可

2.3 日志输出 && 预编译sql

  1. 可以在application.properties中,打开mybatis的日志,并指定输出到控制台。
#指定mybatis输出日志的位置,输出控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
  1. 不需要记住上述配置,左式输入mybatislog,选择-impl的,右式输入std自动填充。
    在这里插入图片描述
    在这里插入图片描述
  2. 测试:删除id大于13的,结果:sql语句,问号是占位符,参数是13,结果是影响一条数据。id需要参数注入,是预编译sql
    @Delete("delete from tb_emp where id >#{id}")
    public int delete(Integer id);

在这里插入图片描述

  1. sql预编译:
    区别:
    1)预编译:预编译是在运行之前,直接使用?作为占位符,已经进行了缓存;运行时识别的是普通字符串,直接将数值填入问号占位符处。

    2)普通sql语句:在运行时填入参数,再进行语法检查和sql编译缓存,可能会造成sql注入。
    在这里插入图片描述
    3)使用#{}和${}区别:正常情况下使用#{},在动态设置使用 ${}
    其中,在面对字符串内的参数时,使用concat字符串拼接函数
concat('%',#{name},'%')

在这里插入图片描述

2.4 sql注入

  1. SQL注入是通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法。
  2. sql注入实例:登录界面
    1)原sql语句
selet count(*) from emp where username='liquor' and password = '12345678';

2)sql注入的输入方法:账户名随意输入,密码输入如下内容:

'or'1'='1

3)被篡改的语句:如下,篡改了sql语句,后置or ‘1’='1’是恒正确的语句,所以where后的条件已经是恒正确语句。此时该语句进入编译流程,会识别错误。

selet count(*) from emp where username='jinyong' and password = ''or'1'='1';
  1. 解决方案实例:
    1)使用预编译
    2)测试:由于预编译使得sql语句的形式固定(已经编译过了,不会识别非法注入的or语句,仅仅是填充参数),输入的参数变为普通的字符串,不会再被注入。
    在这里插入图片描述

2.5 新增操作

  1. 插入操作经常涉及到多个参数,可以使用实体类作为形参,在使用占位符预编译时,#{}内的参数名要与实体类中定义的名称一致
  2. 实例:增加一个员工信息:
  3. EmpMapper:因为函数insert中传递数值的形参是实体类Emp,所以在使用占位符预编译时,#{}内的参数名要与实体类中定义的名称一致,这里的参数名和sql数据库什么没关系,重点是传递参数的形参
    //新增员工
    @Insert("insert into tb_emp(id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time) " +
            "VALUES (#{id},#{username},#{password}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})")
    public void insert(Emp emp);

  1. 测试代码:
    @Test
    public void testInsert(){
        Emp emp = new Emp();
        emp.setUsername("Tom3");
        emp.setName("汤姆3");
        emp.setImage("1.jpg");
        emp.setGender((short)1);
        emp.setJob((short)1);
        emp.setEntrydate(LocalDate.of(2000,1,1));
        emp.setCreateTime(LocalDateTime.now());
        emp.setUpdateTime(LocalDateTime.now());
        emp.setDeptId(1);
        empMapper.insert(emp);
    }

2.6 新增操作下的主键返回功能——@Options

  1. 描述:在数据添加成功后,需要获取插入数据库数据的主键。

  2. 问题:在未注释时,可以正常运行,但通过get函数获取null值。在上述增加操作的测试文件中加一句向控制台输出id的语句行,获取id=null;
    在这里插入图片描述

  3. 语法:会自动将生成的主键值,赋值给对象与之对应的属性变量

    @Options(keyProperty = "主键对应的对象变量名",useGeneratedKeys = true)
  1. 实例:
    1)上述新增代码修改:
    @Options(keyProperty = "id",useGeneratedKeys = true)
    @Insert("insert into tb_emp(id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time) " +
            "VALUES (#{id},#{username},#{password}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})")
    public void insert(Emp emp);

2)测试代码:

    @Test
    public void testInsert(){
        Emp emp = new Emp();
        emp.setUsername("Tom");
        emp.setName("汤姆");
        emp.setImage("1.jpg");
        emp.setGender((short)1);
        emp.setJob((short)1);
        emp.setEntrydate(LocalDate.of(2000,1,1));
        emp.setCreateTime(LocalDateTime.now());
        emp.setUpdateTime(LocalDateTime.now());
        emp.setDeptId(1);
        empMapper.insert(emp);
        System.out.println(emp.getId());
    }

3)控制台结果:
在这里插入图片描述

2.7 更新操作

  1. 更新一般通过主键查询原数据值并修改
  2. 实例:通过id更新
    1)EmpMapper:
    //更新员工
    @Update("update tb_emp set username = #{username}, name = #{name}, gender = #{gender}, image = #{image}," +
            " job = #{job}, entrydate = #{entrydate}, dept_id = #{deptId},update_time = #{updateTime} " +
            "where id = #{id}")
    public void update(Emp emp);

2)测试代码:

    @Test
    public void testUpdate(){
        Emp emp = new Emp();
        emp.setId(20);
        emp.setUsername("T");
        emp.setName("汤姆T");
        emp.setImage("5.jpg");
        emp.setGender((short)1);
        emp.setJob((short)1);
        emp.setEntrydate(LocalDate.of(2000,1,1));
        emp.setCreateTime(LocalDateTime.now());
        emp.setUpdateTime(LocalDateTime.now());
        emp.setDeptId(1);
        empMapper.update(emp);
    }

2.8 查询操作 && 字段名称与实体类名不一致问题

  1. 实例:按照id查询信息
    1)EmpMapper:
    //根据id查询员工
    @Select("select * from tb_emp where id=#{id}")
    public Emp select(Integer id);

2)测试代码:

    @Test
    public void testSelectId(){
        Emp selectIdResult = empMapper.select(1);
        System.out.println(selectIdResult.toString());
    }

3)结果:查询输出的部分数据为null
在这里插入图片描述

  1. 问题原因:
    1)实体类属性名 和 数据库表查询返回的字段名一致,mybatis会自动封装。
    2)如果实体类属性名 和数据库表查询返回的字段名不一致,不能自动封装
    在这里插入图片描述
  2. 解决方案一:在@select的sql语句中给字段起别名,使得别名与实体类的属性一致,不易于读写代码,不常用
    在这里插入图片描述
  3. 方案二:mybatis的注解@Result手动映射封装,代码比较繁琐,使用率不高,其中@Results是集合,column是数据库字段名称,property是映射的名称,与实体类属性名称一致。
    @Results({
            @Result(column = "dept_id",property = "deptId"),
            @Result(column = "create_time",property = "createTime"),
            @Result(column = "update_time",property = "updateTime")
    })
    @Select("select * from tb_emp where id=#{id}")
    public Emp select(Integer id);
  1. 方案三:推荐:开启mybatis驼峰命名自动映射,在application.properties文件中配置,同时,类名和数据库字段名要严格遵守:数据库字段名是下划线连接,属性名是同单词的驼峰
# 开启驼峰命名自动映射
mybatis.configuration.map-underscore-to-camel-case=true

2.9 查询操作——条件查询

  1. 实例:查找名称中包含汤且性别为1的数据
  2. EmpMapper:字符串内使用${},不推荐
    @Select("SELECT * from tb_emp where name like '%${name}%' and gender = #{gender} order by update_time desc ")
    public List<Emp> selectList(String name,short gender);
  1. 测试代码:
    @Test
    public void testSelectList(){

        List<Emp> emps =empMapper.selectList("汤",(short) 1);
        System.out.println(emps);
    }
  1. 使用${}的问题:性能低、不安全、存在SQL注入问题
  2. 解决办法:concat字符串拼接函数
concat('%',#{name},'%')
    @Select("SELECT * from tb_emp where name like concat('%',#{name},'%') and gender = #{gender} order by update_time desc ")
    public List<Emp> selectList(String name,short gender);

备注:本文application.properties文件配置

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/数据库名称
spring.datasource.username=root
spring.datasource.password=12345678
# 将mybatis日志输出在控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# 驼峰命名自动注入
mybatis.configuration.map-underscore-to-camel-case=true
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值