spring(DAY03)

前次作业

编写以下需求对应的SQL语句(使用记事本保存):

  • pms_brand表中插入数据

    • INSERT INTO pms_brand (name, pinyin, logo, description, keywords, sort, sales, product_count, comment_count, positive_comment_count, enable, gmt_create, gmt_modified) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
      
  • 根据id删除pms_brand表中的某1条数据

    • DELETE FROM pms_brand WHERE id=?;
      
  • 根据若干个id批量删除pms_brand表中的数据

    • DELETE FROM pms_brand WHERE id=? OR id=? …… OR id=?;
      
    • DELETE FROM pms_brand WHERE id IN (?, ?, .... ?);
      
  • 根据id修改pms_brand表中的name字段的值

    • UPDATE pms_brand SET name=? WHERE id=?;
      
  • 统计pms_brand表中的数据的数量

    • SELECT count(*) FROM pms_brand;
      
    • 阿里巴巴Java开发手册:
      【强制】不要使用 count(列名)或 count(常量)来替代 count(*),count(*)是 SQL92 定义的
      标准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关。
      说明:count(*)会统计值为 NULL 的行,而 count(列名)不会统计此列为 NULL 值的行。
      
  • 根据name查询pms_brand表中的数据

    • SELECT id, name, pinyin, logo, description, keywords, sort, sales, product_count, comment_count, positive_comment_count, enable, gmt_create, gmt_modified FROM pms_brand WHERE name=?;
      
    • 阿里巴巴Java开发手册:
      【强制】在表查询中,一律不要使用 * 作为查询的字段列表,需要哪些字段必须明确写明。
      说明:1)增加查询分析器解析成本。2)增减字段容易与 resultMap 配置不一致。
      
  • 根据id查询pms_brand表中的数据

    • SELECT id, name, pinyin, logo, description, keywords, sort, sales, product_count, comment_count, positive_comment_count, enable, gmt_create, gmt_modified FROM pms_brand WHERE id=?;
      
  • 查询pms_brand表中所有的数据

    • SELECT id, name, pinyin, logo, description, keywords, sort, sales, product_count, comment_count, positive_comment_count, enable, gmt_create, gmt_modified FROM pms_brand ORDER BY id
      

2. 添加数据库编程的相关依赖

首先,在pom.xml中添加数据库编程的必要依赖项:

<!-- Mybatis整合Spring Boot的依赖项 -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.2</version>
</dependency>
<!-- MySQL的依赖项 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

在Spring Boot项目中,一旦添加以上依赖项,项目将不可以正常启动!

Spring Boot项目默认是开启了自动配置的,当添加了以上数据库编程的依赖项时,就会自动从配置文件中读取连接数据库的URL参数值,如果当前尚未配置此参数,就会启动失败!

***************************
APPLICATION FAILED TO START
***************************

Description:

Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.

Reason: Failed to determine a suitable driver class

src/main/resources下的application.properties是Spring Boot项目的默认主配置文件,当启动项目时,会自动从此文件中读取相关配置,为保证能够正常的使用数据库编程,需要在此文件中添加配置:

spring.datasource.url=jdbc:mysql://localhost:3306/mall_pms?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root

完成后,首先,在src/test/java下默认的包中,找到默认的测试类,先执行默认的contextLoads()测试方法,此测试应该能够通过,如果不能,则表示IDEA出错、依赖项出错。

contextLoads()通过后,在此测试类中补充:

@Autowired
DataSource dataSource;

@Test
void testGetConnection() throws Exception {
    dataSource.getConnection();
}

注意:以上使用到的DataSourcejavax.sql包中的!

执行以上新测试时,会发生与数据库(MySQL)的连接,可以借此检验在application.properties中的配置是否正确!

如果配置的spring.datasource.url中的主机名(localhost)或端口号(3306)错误,或者,MySQL / MariaDB的服务根本没有启动,则会出现以下错误:

com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.

如果在spring.datasource.url中指定的数据库名称有误,或MySQL / MariaDB中确实无此数据库,则会出现以下错误:

java.sql.SQLSyntaxErrorException: Unknown database 'mall_qms'

如果在spring.datasource.url中指定的serverTimezone有误,则会出现以下错误:

java.sql.SQLNonTransientConnectionException: Could not create connection to database server.

Caused by: java.time.zone.ZoneRulesException: Unknown time-zone ID: Asia/ShangHai

如果在spring.datasource.usernamespring.datasource.password中配置的MySQL / MariaDB的用户名或密码错误,则会出现以下某种错误:

java.sql.SQLException: Access denied for user 'rootx'@'localhost' (using password: YES)
java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: YES)
java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: NO)

3. 创建实体类

关于数据表中的字段的数据类型,与Java类中的属性的数据类型的对应关系:

数据表的字段的数据类型Java类中的属性的数据类型
tinyint / smallint / intInteger
bigintLong
char / varchar / text系列String
date_timeLocalDateTime(Java 8)
decimalBigDecimal(Java 8)

关于POJO的设计规范

  • 具有无参数的构造方法;
  • 属性均声明为private的;
  • 生成所有属性对应的规范的Setter和Getter;
  • 生成规范的hashCode()equals()方法;
    • 如果2个对象的hashCode()值相同,则必须保证它们equals()对比的结果为true;如果2个对象的hashCode()值不同,则必须保证它们equals()对比的结果为false
    • 通常,可以使用专业的开发工具生成这2个方法,不必关心这个方法的方法体代码。
  • 【建议,不强制要求】生成(重写)toString()方法;
  • 实现Serializable接口。

使用Lombok可以简化POJO类的编写,在使用之前,需要在项目中添加依赖:

<!-- Lombok的依赖项,主要用于简化实体类的编写 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.20</version>
    <scope>provided</scope>
</dependency>

当添加以上依赖项后,在各POJO类上,只需要添加@Data注解,即可使得Lombok框架在编译期生成各属性对应的Setter & Getter、hashCode()equals()toString()方法。

注意:使用Lombok时,应该(强烈推荐)在开发工具中安装Lombok插件(在IntelliJ IDEA中,点击File > Settings,在Plugins中搜索Lombok并安装),如果未安装,在调用由Lombok生成的方法,或使用相关变量时会提示错误,但不影响运行!

src/main/java根包下,创建pojo.entity子包,并在此子包下创建Brand类:

package cn.tedu.csmall.product.pojo.entity;

import lombok.Data;

import java.io.Serializable;
import java.time.LocalDateTime;

@Data
public class Brand implements Serializable {

    private Long id;
    private String name;
    private String pinyin;
    private String logo;
    private String description;
    private String keywords;
    private Integer sort;
    private Integer sales;
    private Integer productCount;
    private Integer commentCount;
    private Integer positiveCommentCount;
    private Integer enable;
    private LocalDateTime gmtCreate;
    private LocalDateTime gmtModified;
    
}

4. 关于Mybatis框架

Mybatis框架的主要作用是简化数据库编程。

5. Mybatis的用法

使用Mybatis主要需要:

  • 编写处理数据的抽象方法
    • 抽象方法必须声明在接口中,因为Mybatis框架的底层实现是基于接口的代理模式
    • 接口通常以Mapper作为名称的最后一个单词
  • 配置抽象方法对应的SQL语句

关于接口,必须使得Mybatis框架能够明确这些Mapper接口的位置,或者说,使得Mybatis知道有哪些Mapper接口,可以采取的做法有(二选一):

  • 【不推荐】在每一个Mapper接口上添加@Mapper注解
  • 【推荐】在配置类上添加@MapperScan注解,并在此注解中配置参数,参数值就是Mapper接口所在的根包,并且,确保各Mapper接口在此包下
    • 配置类:在项目的根包下(包含根包下的子孙包下),添加了@Configuration注解的类,就是配置类

关于抽象方法的声明原则:

  • 返回值类型:如果要执行的SQL是增、删、改类型的,推荐使用int作为返回值类型,表示“受影响的行数”,其实,也可以使用void,并不推荐这样使用;如果要执行的SQL是查询类型的,只需要保证返回值类型足以封装所需的查询结果即可

  • 方法名称:自定义,但不要重载

    • 阿里巴巴Java开发手册:
      【参考】
      获取单个对象的方法用 get 做前缀
      获取多个对象的方法用 list 做前缀
      获取统计值的方法用 count 做前缀
      插入的方法用 save/insert 做前缀
      删除的方法用 remove/delete 做前缀
      修改的方法用 update 做前缀
      
  • 参数列表:如果需要执行的SQL语句有多个参数,并且具有相关性,则应该将这些参数进行封装,并使用封装的类型作为抽象方法的参数

关于配置抽象方法对应的SQL语句,可以(二选一):

  • 【不推荐】使用@Insert等注解配置SQL语句,并使用相关注解(例如@Result等)完成相关配置
  • 【推荐】使用专门的XML文件配置SQL语句及相关配置
    • SQL语句更加直观,易于阅读
    • 相关配置更加直观,易于复用
    • 易于实现与DBA(Database Administrator)协同工作

关于配置SQL语句的XML文件:

  • 根标签必须是<mapper>
  • 必须配置<mapper>标签的namespace属性,此属性的值是对应的Mapper接口的全限定名
  • <mapper>标签的子级,使用<insert> / <delete> / <update> / <select>标签配置SQL语句
  • 关于<insert>等标签,都必须配置id属性,取值为对应的抽象方法的名称(不包括抽象方法的签名的其它部分,例如,不需要括号等)
  • 关于<select>标签,必须配置resultTyperesultMap这2个属性中的其中1个
  • <insert>等标签的内部,编写SQL语句,注意:在<insert>标签的内容不要写任何注释,因为写在此处的注释都会被视为SQL语句的一部分

6. 使用Mybatis实现:插入品牌数据

src/main/java下的根包下,创建config子包,并在此子包下创建MybatisConfiguration类,在此类上通过注解配置Mapper接口的根包:

@Configuration
@MapperScan("cn.tedu.csmall.product.mapper")
public class MybatisConfiguration {
}

src/main/java下的根包下,创建mapper子包,并在此子包下创建BrandMapper接口,在接口中添加抽象方法:

public interface BrandMapper {
    int insert(Brand brand);
}

从 http://doc.canglaoshi.org/config/Mapper.xml.zip 下载压缩包,解压得到SomeMapper.xml文件。

src/main/resources下,创建mapper文件夹(文件夹名称是自定义的),并将SomeMapper.xml复制到此文件夹中,此XML文件就是用于配置抽象方法对应的SQL语句的文件。

然后,在application.properties中添加配置,以指定这些XML文件的位置:

# 配置SQL的XML文件的位置
mybatis.mapper-locations=classpath:mapper/*.xml

并且,在SomeMapper.xml重命名为BrandMapper.xml,在此文件中配置:

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

<mapper namespace="cn.tedu.csmall.product.mapper.BrandMapper">

    <insert id="insert">
        INSERT INTO pms_brand (
            name, pinyin, logo, description, keywords,
            sort, sales, product_count, comment_count, positive_comment_count,
            enable
        ) VALUES (
            #{name}, #{pinyin}, #{logo}, #{description}, #{keywords},
            #{sort}, #{sales}, #{productCount}, #{commentCount}, #{positiveCommentCount},
            #{enable}
        )
    </insert>

</mapper>

至此,“插入品牌数据”的功能已经完成!

接下来,应该及时测试以上功能是否可以正常运行!

src/test/java下的根包下,创建mapper子包,在此子包中创建BrandMapperTests测试类。

注意:所有的测试类必须在根包下!

注意:测试类的类名,不可以与被测试的类名/接口名相同!

测试代码如下:

package cn.tedu.csmall.product.mapper;

import cn.tedu.csmall.product.pojo.entity.Brand;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class BrandMapperTests {

    @Autowired
    BrandMapper mapper;
    
    @Test
    void testInsert() {
        Brand brand = new Brand();
        brand.setName("测试品牌998");

        int rows = mapper.insert(brand);
        System.out.printf("插入品牌完成,受影响的行数=" + rows);
    }

}

如果此前没有在配置类中正确的使用@MapperScan配置Mapper接口的根包,将出现以下错误:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'cn.tedu.csmall.product.mapper.BrandMapper' available: expected at least 1 bean which qualifies as autowire candidate.

如果:

  • 此前没有在application.properties中正确的配置XML文件的位置
  • 在XML中的<mapper>标签上配置的namespace值有误
  • 在XML中的<insert>等标签上配置的id值有误

将出现以下错误:

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): cn.tedu.csmall.product.mapper.BrandMapper.insert

作业

  1. 写出所有数据表的实体类
  2. 创建新的接口、新的XML文件,实现:插入类别数据、插入相册数据,完成后,使用新的测试类进行测试
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值