JavaEE进阶:MyBatis操作数据库(进阶)

1.动态SQL

动态SQL是mybatis的最强大特性之一,能够完成不同条件下,SQL语句的拼接.

1.1 <if>标签

在我们注册用户的时候,有些是必填信息,有些是选填信息.

这个时候,我们创建新用户的这个SQL语句就是不确定的.比如说有的用户填gender,有的用户不填gender,这时候SQL语句就会发生变化.

这时候我们就需要用动态标签来判断了.

当我们创建一个用户的时候,需要使用insert语句.

但是有些信息用户并不是必填项,当用户没有填的时候,就应该更改SQL语句.

如果我们用现在这个SQL,然后只传入两个参数,就会出现下面的情况,就会报错.

正常情况下,我们应该是如果需要username,password.

SQL语句应该是 insert into userinfo(username,'password') values(#{username},#{password})

如果还填了gender,SQL语句应该是:

insert into userinfo(username,'password',gender) values(#{username},#{password},#{gender})

我们需要的是这种动态的SQL.而不是和报错信息中的那样,不填的值为null.

要想实现这种效果,我们就需要用到<if>标签了.用if标签判断是否为空,如果为空,就不去添加这个字段进入SQL.

再次运行测试用例.

这时候我们就会发现,SQL语句倒是没有多余的信息了,但是后面多出来个逗号.还是会报错.

如果我们把,放在前面,当某个信息不填的时候一样也会报错.

这个时候,我们就需要用到<trim>标签了

1.2 <trim>标签

<trim>标签有四个属性.

用trim标签中的suffixOverrides去掉后缀的","再次运行程序.

这时候,我们再次运行代码,插入数据,就可以正确插入了.

1.3 <where>标签

在各种购物平台中,我们除了会进行排序操作以外,还会进行筛选操作.

这个时候,就需要用到where语句进行条件查询.用户对象中属性不为null的都可以作为查询条件.

原SQL:

使用where标签:

使用where标签之后,where标签会自动去除子句开头的and或者or.

试着查询年龄18的用户信息.

就可以查询出来结果.

1.4 <set>标签

需求:根据传入的用户对象属性来更新用户数据,可以使用标签来指定动态内容.

根据id更改username

1.5 <foreach>标签

对集合进行遍历可以使用该标签.

删除年龄为18,20,21的用户信息.

这时候我们就需要使用foreach标签来进行循环遍历了.

运行代码看看效果.

1.6 <include>标签

在xml映射文件中配置的SQL,可能会存在很多重复的片段,此时就会有很多冗余的代码.

这时候,就可以用include标签来解决这个问题.

我们可以对重复的代码片段进行抽取,将其通过<sql>标签封装到一个SQL片段,然后再通过<include>标签进行引用.

<sql>:定义可重用的sql片段.

<include>:通过属性refid,指定包含的SQL片段.

通过这两个标签,可以重复使用同一个SQL片段.

运行代码,看看效果.

2.案例练习

2.1 表白墙

在之前的案例中,我们写了表白墙.

但是服务器一但重启,数据仍然会丢失.

想要数据不丢失,就得将数据存储在数据库中.

接下来,我们借助mybatis来实现这个功能.

2.1.1 创建表

SQL代码:

sql 复制代码
DROP TABLE IF EXISTS message_info;
CREATE TABLE `message_info` (
    `id` INT ( 11 ) NOT NULL AUTO_INCREMENT,
    `from` VARCHAR ( 127 ) NOT NULL,
    `to` VARCHAR ( 127 ) NOT NULL,
    `message` VARCHAR ( 256 ) NOT 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;

2.1.2 引入MyBatis和MySQL驱动依赖

java 复制代码
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>4.0.1</version>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>

2.1.3 配置MySQL账号密码

java 复制代码
spring:
  application:
    name: confessionWall
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true

2.1.4 编写后端代码

创建实体类:

java 复制代码
@Data
public class message {
    private String id;
    private String from;
    private String to;
    private String message;
    private Integer deleteFlag;
    private String creatTime;
    private String updateTime;
}

创建MessageInfoMapper:

编写MyBatis代码:

java 复制代码
public interface MessageInfoMapper {
    //插入一条新信息
    @Insert("insert into message_info(`from`, `to`, message) VALUES (#{from},#{to},#{message})")
    Integer insert(Message message);
    //获取所有消息
    @Select("select `from`,`to`,message from message_info where delete_flag = 0")
    List<Message> selectAll();
}

创建MessageService:

Service层用来处理业务逻辑:

这里的业务逻辑很简单,只需要添加数据到数据库,以及从数据库中获取数据即可.

java 复制代码
public class MessageService {
    @Autowired
    private MessageInfoMapper messageInfoMapper;
    public Integer insert(Message message){
        return messageInfoMapper.insert(message);
    }
    public List<Message> selectAll(){
        return messageInfoMapper.selectAll();
    }
}

创建MessageController:

调用Service层,从数据库中获取消息.

从前端获取到message信息然后通过server层添加到数据库.

java 复制代码
@RestController
@RequestMapping("/message")
public class MessageController {
    @Autowired
    private MessageService messageService;
    //获取所有消息
    @RequestMapping("/getMessage")
    public List<Message> getMessage(){
        return messageService.selectAll();
    }
    //点击提交按钮,添加一条数据
    @RequestMapping("/push")
    public Boolean push(Message message){
        //判断数据是否为空
        if(StringUtils.hasLength(message.getFrom())
                && StringUtils.hasLength(message.getTo())
                && StringUtils.hasLength(message.getMessage())
        ){
            messageService.insert(message);
            return true;
        }
        return false;
    }
}

2.1.5 测试

运行程序,输入信息,点击提交,观察数据库是否成功添加.

点击提交,观察数据库.成功添加,

重新运行程序,记录依然存在

2.2 图书管理系统

前面的图书管理系统,我们只做了个用户登入界面和图书列表,并且数据是mock的.

接下来我们把其他的功能完善.

功能列表: 用户登入/图书列表/图书增删改查/翻页功能/强制登入

2.2.1 数据库表设计

java 复制代码
-- 创建数据库
DROP DATABASE IF EXISTS book_test;

CREATE DATABASE book_test DEFAULT CHARACTER SET utf8mb4;

USE book_test;
-- 用户表
DROP TABLE IF EXISTS user_info;
CREATE TABLE user_info (
    `id` INT NOT NULL AUTO_INCREMENT,
    `user_name` VARCHAR ( 128 ) NOT NULL,
    `password` VARCHAR ( 128 ) NOT NULL,
    `delete_flag` TINYINT ( 4 ) NULL DEFAULT 0,
    `create_time` DATETIME DEFAULT now(),
    `update_time` DATETIME DEFAULT now() ON UPDATE now(),
    PRIMARY KEY ( `id` ),
    UNIQUE INDEX `user_name_UNIQUE` ( `user_name` ASC ))
    ENGINE = INNODB DEFAULT CHARACTER
    SET = utf8mb4 COMMENT = '用户表';

-- 图书表
DROP TABLE IF EXISTS book_info;
CREATE TABLE `book_info` (
    `id` INT ( 11 ) NOT NULL AUTO_INCREMENT,
    `book_name` VARCHAR ( 127 ) NOT NULL,
    `author` VARCHAR ( 127 ) NOT NULL,
    `count` INT ( 11 ) NOT NULL,
    `price` DECIMAL (7,2) NOT NULL,
    `publish` VARCHAR ( 256 ) NOT NULL,
    `status` TINYINT ( 4 ) DEFAULT 1 COMMENT '0-无效, 1-正常, 2-不允许借阅',
    `create_time` DATETIME DEFAULT now(),
    `update_time` DATETIME DEFAULT now() ON UPDATE now(),
    PRIMARY KEY ( `id` )
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;

-- 初始化数据
INSERT INTO user_info ( user_name, PASSWORD ) VALUES ( "admin", "admin" );
INSERT INTO user_info ( user_name, PASSWORD ) VALUES ( "zhangsan", "123456" );

-- 初始化图书数据
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES ('活着', '余华', 29, 22.00, '北京文艺出版社');
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES ('平凡的世界', '路遥', 5, 98.56, '北京十月文艺出版社');
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES ('三体', '刘慈欣', 9, 102.67, '重庆出版社');
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES ('金字塔原理', '麦肯锡', 16, 178.00, '民主与建设出版社');

创建完成后就有表book_info和表user_info

2.2.2 引入MyBatis和MySQL驱动依赖

添加这两个依赖

2.2.3 配置数据库&日志

java 复制代码
# 数据库连接配置
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/book_test?characterEncoding=utf8&useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
  configuration:
    map-underscore-to-camel-case: true #配置驼峰自动转换
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #打印sql语句
# 设置日志文件的文件名
logging:
  file:
    name: spring-book.log

2.2.4 Model创建

UserInfo用户类:

java 复制代码
public class UserInfo {
    private Integer id;
    private String userName;
    private String password;
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
}

BookInfo图书类:

java 复制代码
public class BookInfo {
    //图书ID
    private Integer id;
    //书名
    private String bookName;
    //作者
    private String author;
    //数量
    private Integer count;
    //定价
    private BigDecimal price;
    //出版社
    private String publish;
    //状态 0-无效 1-允许借阅 2-不允许借阅
    private Integer status;
    private String statusCN;
    //创建时间
    private Date createTime;
    //更新时间
    private Date updateTime;
}

2.2.5 用户登入

创建UserInfoMapper,用来从数据库中查询是否有该用户的信息,用于后面校验登入信息

java 复制代码
@Mapper
public interface UserInfoMapper {
    //从数据库中查询是否有这个用户,返回用户信息
    @Select("select user_name,`password` from user_info where user_name = #{username} and delete_flag = 0")
    UserInfo selectByUsername(String username);
}

创建UserService,处理用户登入逻辑.

java 复制代码
@Service
public class UserService {
    @Autowired
    private UserInfoMapper userInfoMapper;

    public UserInfo selectByUsername(String username) {
        return userInfoMapper.selectByUsername(username);
    }
}

创建UserController,注入UserService,通过UserService的selectByUsername方法查询数据库中是否存在该用户信息,不存在返回false,存在则校验密码是否正确.

java 复制代码
public class UserController {
    @Autowired
    private UserService userService;
    @RequestMapping("login")
    public Boolean login(String username, String password, HttpSession session) {
        if(!StringUtils.hasLength(username)|| !StringUtils.hasLength(password)){
            return false;
        }
        //从数据库中查询是否存在用户
        UserInfo userInfo = userService.selectByUsername(username);
        if(userInfo == null){
            return false;
        }
        if(userInfo!=null && password.equals(userInfo.getPassword())){
            session.setAttribute("session_user_key", userInfo);
            return true;
        }
        return false;
    }
}

测试程序.

输入数据库中存在的账号密码,登入成功

2.2.6添加图书

约定前后端交互接口: book/addBook

先补充BookController代码:

java 复制代码
    @RequestMapping("/addBook")
    public String addBook(BookInfo bookInfo){
        //打印日志
        log.info("添加图书:" + bookInfo);
        //判断图书信息是否为空
        if(!StringUtils.hasLength(bookInfo.getBookName())
                || !StringUtils.hasLength(bookInfo.getAuthor())
                || !StringUtils.hasLength(bookInfo.getPublish())
                || bookInfo.getPrice() == null
                || bookInfo.getCount() == null
                || bookInfo.getStatus() == null
        ){
            return "信息不全,请补充图书信息";
        }
        Integer result = bookService.addBook(bookInfo);
        if(result == 1){
            return "";
        }
        return "添加图书失败";
    }

再补充BookService代码:

java 复制代码
    public Integer addBook(BookInfo bookInfo) {
        return bookInfoMapper.insertNewBook(bookInfo);
    }

最后编写SQL语句:

java 复制代码
    @Insert("insert into book_info(book_name,author,count,price,publish,status) " +
            "values(#{bookName},#{author},#{count},#{price},#{publish},#{status})")
    Integer insertNewBook(BookInfo bookInfo);

写完后端代码之后,如果对前端相关内容不会修改,可以先用postman来进行测试.

发送请求后可以看到数据库中确实添加了一条数据.

前端代码:

修改add()方法:

程序测试:

点击确定,在数据库中成功添加一条数据

2.2.7图书列表

可以看到,我们添加图书之后,太哦转到图书列表页面,并没有显示刚刚添加的图书,这是因为之前我们在写这块代码的时候,图书信息是mock的,并不是从数据库中读取.

接下来我们来实现图书列表功能.

java 复制代码
    @RequestMapping("getList")
    public List<BookInfo> getList(){
        return bookService.getList();
    }
java 复制代码
    public List<BookInfo> getList(){
        List<BookInfo> list = bookInfoMapper.selectAll();
        for(BookInfo bookInfo : list){
            bookInfo.setStatusCN(BookStatus.getDescByCode(bookInfo.getStatus()));
        }
        return list;
    }
java 复制代码
    @Select("select id,book_name,author,count,price,publish,status from book_info where status = 1")
    List<BookInfo> selectAll();

添加了个枚举类,用来枚举图书状态,因为在数据库中status是状态码,而不是状态,所以我们要在service层中,先获取到数据库中的状态码,再设置状态.

java 复制代码
public enum BookStatus {
    DELETE(0, "无效"),
    NORMAL(1, "可借"),
    FORBIDDEN(2, "不可借");
    private Integer code;
    private String desc;
    BookStatus(Integer code, String message) {
        this.code = code;
        this.desc = message;
    }
    public static String getDescByCode(Integer code) {
        switch ( code){
            case 0:
                return DELETE.desc;
            case 1:
                return NORMAL.desc;
            case 2:
                return FORBIDDEN.desc;
            default:
                return null;
        }
    }
}

重新进入页面,我们就可以看到从数据库中拿到的真实信息了

2.2.8 翻页功能

先往数据库中添加多一点信息.当信息变多了之后我们会发现全在一页上.并不能像我们想象的那样分页.

需求:每一页展示十条数据.

想要实现这个功能,需要在数据库中进行分页查询.我们需要使用limit关键字.

查询第一页:

java 复制代码
select * from book_info limit 0,10;

查询第二页:

java 复制代码
select * from book_info limit 10,10;

观察上述SQL我们可以发现,在查询的时候,索引是一直在改变,但是每页显示的条数固定不变.

前端发起请求查询,需要两个参数,currentPage:当前页数,pageSize每页显示条数.

后端响应时,需要给前端的数据,records:所查询到的数据列表,total:总页数.

java 复制代码
@Data
public class Pageinfo {
    //当前页数
    private Integer currentPage;
    //每页显示条数
    private Integer pageSize;
    //索引
    private Integer offset;

    public Integer getOffset(){
        return (currentPage - 1) * pageSize;
    }
}

约定前后端交互接口:

前端给服务器发送一个/book/getListByPage这样的HTTP请求,通过currentPage告诉服务器,当前请求为第几页的数据,后端根据请求参数,返回对应页数的数据.

创建给前端返回的结果类.

java 复制代码
@Data
public class PageResult<T> {
    //总记录数
    private Integer total;
    //当前页中的数据
    private List<T> records;
    //当前页码
    private PageInfo pageInfo;

    public PageResult(List<T> records, Integer total, PageInfo pageInfo) {
        this.pageInfo = pageInfo;
        this.records = records;
        this.total = total;
    }
}

把原来的getList方法修改:

java 复制代码
    @RequestMapping("/getBookListByPage")
    public PageResult<BookInfo> getBookListByPage(PageInfo pageinfo){
        return bookService.getBookListByPage(pageinfo);
    }

BookService修改:

获取到前端发来的请求页码,然后获取到索引,然后查询数据库,得到请求页码的数据,和总数.

构建新对象返回给前端.

java 复制代码
    public PageResult<BookInfo> getBookListByPage(PageInfo pageInfo) {
        Integer setoff = pageInfo.getOffset();
        Integer pagesize = pageInfo.getPageSize();
        List<BookInfo> list = bookInfoMapper.seletByCurrentPage(setoff,pagesize);
        for(BookInfo bookInfo : list){
            bookInfo.setStatusCN(BookStatus.getDescByCode(bookInfo.getStatus()));
        }
        Integer count = bookInfoMapper.count();
        return new PageResult<>(list,count,pageInfo);
    }

BookInfoMapper:

java 复制代码
    @Select("select id,book_name,author,count,price,publish,status from book_info where status != 0  order by id asc limit #{currentPage},#{pageSize}")
    List<BookInfo> seletByCurrentPage(Integer currentPage,Integer pageSize);

    @Select("select count(*) from book_test.book_info where status != 0")
    Integer count();

最后修改前端代码

运行程序,可以正常展示不同页码中的图书信息:

2.2.9 修改图书

约定前后端接口:

/book/queryBookById 进入修改页面显示当前图书信息

/book/updateBook 点击修改按钮,修改图书信息

controller层:

java 复制代码
    @RequestMapping("/queryBookById")
    public BookInfo queryBookById(Integer bookId){
        log.info("查询图书:"+ bookId);
        return bookService.queryBookById(bookId);
    }
    @RequestMapping("/updateBook")
    public String updateBook(BookInfo bookInfo){
        if(bookInfo.getId()<=0){
            return "参数不正确";
        }
        log.info("修改图书:"+ bookInfo);
        try{
            bookService.updateBook(bookInfo);
            return "";
        } catch (Exception e){
            log.error("修改图书失败",e);
            return e.getMessage();
        }

    }

service层:

java 复制代码
    public BookInfo queryBookById(Integer bookId) {
        return bookInfoMapper.selectById(bookId);
    }

    public void updateBook(BookInfo bookInfo) {
        bookInfoMapper.updateBook(bookInfo);
    }

mapper层:

java 复制代码
    @Select("select id,book_name,author,count,price,publish,status from book_info where status != 0 and id = #{id}")
    BookInfo selectById(Integer id);

    //动态SQL用注解不好实现,我们采用xml方式实现
    void updateBook(BookInfo bookInfo);

xml代码:

java 复制代码
    <update id="updateBook">
        update book_info
        <set>
            <if test="bookName!=null">
                book_name = #{bookName},
            </if>
            <if test="author!=null">
                author = #{author},
            </if>
            <if test="price!=null">
                price = #{price},
            </if>
            <if test="count!=null">
                count = #{count},
            </if>
            <if test="publish!=null">
                publish = #{publish},
            </if>
            <if test="status!=null">
                status = #{status},
            </if>
        </set>
        where id = #{id}
    </update>

运行程序,结果符合预期,可以正常展现图书信息以及内容.

修改内容也可以正常修改.

2.2.10 删除图书

我们说的删除指的是逻辑删除.也就是将status设置为0

BookController:

java 复制代码
    @RequestMapping("/deleteBook")
    public String deleteBook(Integer bookId){
        log.info("删除图书:"+ bookId);
        try{
            bookService.deleteBook(bookId);
            return "";
        } catch (Exception e){
            log.error("删除图书失败",e);
            return e.getMessage();
        }
    }

BookService:

java 复制代码
    public void deleteBook(Integer bookId) {
        bookInfoMapper.deleteBook(bookId);
    }

mapper:

java 复制代码
    @Update("update book_info set status = 0 where id = #{bookId}")
    void deleteBook(Integer bookId);

前端:

测试程序,点击删除:

图书从列表中消失,查看数据库,status设置为0

2.2.11 批量删除

批量删除其实就是批量修改数据.

BookController:

java 复制代码
    @RequestMapping("batchDeleteBook")
    public String batchDeleteBook(@RequestParam List<Integer> ids){
        log.info("批量删除图书:"+ ids);
        try{
            bookService.deleteBookByIds(ids);
            return "";
        } catch (Exception e){
            log.error("批量删除图书失败",e);
            return e.getMessage();
        }
    }

BookService:

java 复制代码
    public void deleteBookByIds(List<Integer> bookIds) {
        bookInfoMapper.deleteBookByIds(bookIds);
    }

SQL:

java 复制代码
    <delete id="deleteBookByIds">
        update book_info
        set status = 0
        where id in
        <foreach item="item" index="index" collection="bookIds" open="(" separator="," close=")">
            #{item}
        </foreach>
    </delete>

前端:

测试程序:

点击确定,勾选书籍在列表中消失.

2.2.12 强制登入

虽然我们做了用户登入,但是我们发现,即使不登入,依然可以操作图书.

这是有极大风险的.所以我们需要强制登入.

我们之前已经将用户信息存储在了session中,那么我们就可以通过session中的信息来判断用户是否登入.

如果session中可以拿到用户信息,那么用户已经登入,可以进行后续操作,如果获取不到信息,就不能进行后续操作.要跳转到登入页面.

就以图书列表接口为例:查询到的结果不能判断用户是否登入

这个时候我们加一个属性告知后端的状态以及出错的原因.

当前只是图书列表一个功能,添加这个字段对我们的代码修改量是巨大的.我们可以对后端返回的数据进行一个包装.

设置一个返回结果,有返回数据,编码和错误信息

再降常数值放在同一个类里面,这样籽符合高内聚低耦合的思想.

修改后端代码.添加session判定.

最后修改前端代码.

重新运行程序.可以看到当我们没有登入的时候,就会强制跳转到登入页面

可以看到,我们想要实现强制登入这个功能,需要把所有接口都要改动,这个是很麻烦的,所以springboot也考虑到了这个,在后面的章节中,我们会学习有关拦截器相关知识,到时候会有更简单的方法来实现强制登入.

所以这里就只对图书列表功能进行修改.

3.MyBatis Generator

MyBatis Generator是一个为MyBatis框架设计的代码生成工具, 它可以根据数据库表结构自动生成相应的Java Model, Mapper接口以及SQL映射文件, 简化数据访问层的编码工作, 使得开发者可以更专注于业务逻辑的实现.

接下来我们看下, 如何使用MyBatis Generator 来生成代码.

3.1引入插件

java 复制代码
<plugin>
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-maven-plugin</artifactId>
    <version>1.3.6</version>
    <executions>
        <execution>
            <id>Generate MyBatis Artifacts</id>
            <phase>deploy</phase>
            <goals>
                <goal>generate</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <!--generator配置文件所在位置-->
        <configurationFile>src/main/resources/mybatisGenerator/generatorConfig.xml</configurationFile>
        <!-- 允许覆盖生成的文件,mapxml不会覆盖,采用追加的方式-->
        <overwrite>true</overwrite>
        <verbose>true</verbose>
        <!--将当前pom的依赖项添加到生成器的类路径中-->
        <includeCompileDependencies>true</includeCompileDependencies>
    </configuration>
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>
    </dependencies>
</plugin>

3.2 添加generatorGonfig.xml并修改

创建对应路径的文件.

完善文件内容:

java 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<!-- 配置生成器 -->
<generatorConfiguration>
    <!-- 一个数据库一个context -->
    <context id="MysqlTables" targetRuntime="MyBatis3Simple">
        <!--禁用自动生成的注释-->
        <commentGenerator>
            <property name="suppressDate" value="true"/>
            <property name="suppressAllComments" value="true" />
        </commentGenerator>
        <!--数据库连接信息-->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://127.0.0.1:3306/java_blog_spring?serverTimezone=Asia/Shanghai&amp;nullCatalogMeansCurrent=true"
                        userId="root"
                        password="root">
        </jdbcConnection>
        <!-- 生成实体类, 配置路径 -->
        <javaModelGenerator targetPackage="com.example.demo.model"
                            targetProject="src/main/java" >
            <property name="enableSubPackages" value="false"/>
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>
        <!-- 生成mapxml文件 -->
        <sqlMapGenerator targetPackage="mapper"
                          targetProject="src/main/resources" >
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>
        <!-- 生成mapxml对应client, 也就是接口dao -->
        <javaClientGenerator targetPackage="com.example.demo.mapper"
                              targetProject="src/main/java" type="XMLMAPPER" >
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>
        <!-- table可以有多个,tableName表示要匹配的数据库表 -->
        <table tableName="user" domainObjectName="UserInfo"
               enableSelectByExample="true" enableDeleteByExample="true" enableDeleteByPrimaryKey="true"
               enableCountByExample="true"
               enableUpdateByExample="true">
            <!-- 类的属性是否用数据库中的真实字段名做为属性名, 不指定这个属性会自动转换 _ 为驼峰命名规则 -->
            <property name="useActualColumnNames" value="false" />
            <!-- 数据库表主键 -->
            <generatedKey column="id" sqlStatement="Mysql" identity="true" />
        </table>
    </context>
</generatorConfiguration>

再右边的Maven中找到这个插件,然后双击运行即可.

相关推荐
我是一颗柠檬1 小时前
【MySQL全面教学】MySQL锁机制与并发控制Day10(2026年)
数据库·sql·mysql·database
代码中介商2 小时前
B树:数据库索引的高效基石
数据结构·数据库
fen_fen2 小时前
Oracle12,新增自增主键表和批量插入数据
数据库·sql·mysql
deepin_sir2 小时前
11 - 模块与包
前端·数据库·python
念恒123062 小时前
MySQL索引
数据库·mysql
Lao A(zhou liang)的菜园2 小时前
如何快速诊断Oracle性能问题?
数据库·oracle
铁皮哥2 小时前
【agent 开发】Claude Code 的 Skill 是怎么被加载的?从 name/description 到 SKILL.md 再到资源文件
java·服务器·数据库·python·gitee·github·软件工程
罗超驿2 小时前
6.Java多线程详解:Thread类、线程属性与start()方法深度解析
java·开发语言·面试·java-ee
一只fish2 小时前
Oracle官方文档翻译《Database Concepts 26ai》第14章-物理存储结构
数据库·oracle