初学者idea web项目搭建之路(五) mybatis

前言

之前,在spring boot篇中就遇到了启动失败的问题,原因呢就是自动加载数据源失败,当时呢,是用下面这一句,取消自动加载数据源先回避了这个问题,现在呢,要引入mybatis,我们的数据源自然是要配置配置了。

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

同理,再开始之前,我们先摆出我的资料。spring boot+mybatis整合mybatisSpringBoot数据源配置,ok,大致阅读了一下资料,有个底了。

1.引入依赖

因为新建项目的时候选了Mybatis,所以依赖是已经有了的,就算没点,百度一下Mybatis的依赖也很简单。

 implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.0.0'

2.数据源配置

看完之后脑子里印象最深的就是这个了。在resource目录下,新建application.yml配置文件。好了把@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)更改为@SpringBootApplication() 进行启动。报错,提示com.mysql.jdbc.Driver需要更换为com.mysql.cj.jdbc.Driver。按提示修改,启动正常说明数据源接入成功了。

#数据源配置 jdbc
spring:
  datasource:
    url: jdbc:mysql://localhost:3307/ticketsellingsystem?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
    driverClassName: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456
#mybatis配置
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: org.ironman.ticketsellingsystem.entity
  type-handlers-package: org.ironman.ticketsellingsystem.dao

上述配置理解应该很容易,都是常见的。

url:数据库地址。

driverClassName:驱动,jdbc。

username:数据库账号。

password:数据库密码。

mapper-location:mybatis写了sql语句的xml文件路径。

type-aliasses-package:实体类的路径

type-handlers-package:dao的路径。

其实还有很多的配置可以设置,但是,现在的话,我们只需要这么多就行了。当然这也只是配置数据源其中的方式之一。

当然配置也是不止这么点,例如URL的最后一位。

&serverTimezone=UTC

前面写的时候,我是没有加的,后来写demo的时候报错了,说是什么数据库时区设置问题,就加上了这一条。

3.简单demo

因为手里头有现成的项目,也有搞web的同学的demo,所以对具体的流程,还是略有了解的,我们就简单的来一个查询语句走一遍吧。

第一步,数据库建了个表。

初学者idea web项目搭建之路(五) mybatis


第二步,对应的实体类。TestEntity,注意与数据库的表属性名一致哦,不然肯定会出错的。

package org.ironman.ticketsellingsystem.entity;

public class TestEntity {

    private int  id;
    private String username;

    public int  getId() {
        return id;
    }
    public void setId(int  id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }

}

第三步,dao层。用mybatis其实就是写了一下接口,每个方法都是一个操作,如下,是一个查询操作。

package org.ironman.ticketsellingsystem.dao;

import org.ironman.ticketsellingsystem.entity.TestEntity;

public interface TestDao {
    TestEntity selectUserName(int  id);
}

这里的话,形参,是你查询条件需要的数据,而返回值的类型,你可以自定义。单个可以直接用实体类,多个则用List<entity>这种形式,其他的,慢慢学吧。


第四步,sql语句,mybatis的sql语句是存放在xml文件中的,而这些xml文件,则是存放在之前mybatis配置中设置的文件路径下。基本上一个dao,对应一个mybatis的mapper.xml。

ok,我们在resource/mapper文件夹下,新建一个TestDaoMapper.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="org.ironman.ticketsellingsystem.dao.TestDao">
    <select id="selectUserName" parameterType="int" resultType="TestEntity">
    select * from test where id = #{id}
  </select>
</mapper>

一个简单的查询操作如上所示。ok,这些东西都挺重要的,有半点差错,就肯定会报错,我是踩了。

namespace:命名空间一定要定位到指定的Dao,不然会有Mapper失败的情况。如这里是TestDao。

id:TestDao中对应的方法名,必须一致。

parameterType:输入数据类型与形参一致

resultType:输出数据类型与返回值类型一致

#{id}: TestDao中的形参名,相当于以前的用的 ?标签。查询条件的值就靠它了。


第五步,service,首先定义一些接口,然后实现它,一般实现类反正service下的impl下,后缀也加上Impl

package org.ironman.ticketsellingsystem.service;

import org.ironman.ticketsellingsystem.entity.TestEntity;

public interface TestService {
    TestEntity getUserNameById(int  id);
}
package org.ironman.ticketsellingsystem.service.impl;

import org.ironman.ticketsellingsystem.dao.TestDao;
import org.ironman.ticketsellingsystem.entity.TestEntity;
import org.ironman.ticketsellingsystem.service.TestService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service("TestService")
public class TestServiceImpl implements TestService {
    @Resource
    private TestDao testDao;
    @Override
    public TestEntity getUserNameById(int id) {
        //业务逻辑代码
        return testDao.selectUserName(id);
    }
}

TestService:没什么好说的,应该就是定义一系列逻辑操作的接口,例如定义一个检查账号密码是否正确的方法,一个查询的方法,要在检查账号登录之后查询查询,当然这些方法要在TestServiceImpl类中实现它。然后有两个注解@Service和@Resource,如果要正常使用肯定是配置注解的,所以很重要。


第六步,模板页面,前面我们在引入模板引擎的时候就写好了这个界面。test.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>im test page</title>
</head>
<body>
<p th:text="${hello}">Welcome to our grocery store!</p>
</body>

第七步,controller,修改一下我们之前的TestController,将数据替换为从数据中查询的数据。

package org.ironman.ticketsellingsystem.controller;


import org.ironman.ticketsellingsystem.entity.TestEntity;
import org.ironman.ticketsellingsystem.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.HashMap;
import java.util.Map;
//@Controller 和 @RestController 是有区别的。@RestController 相当于@[email protected]
@Controller
public class TestController {
    @Autowired
    private TestService testService;
    @RequestMapping("/test")
    public String index(Model model) {
        TestEntity testEntity=testService.getUserNameById(1);
       // model.addAttribute("hello", "hello world");
        model.addAttribute("hello", testEntity.getUsername());
        return "test";
    }
}

运行后,结果如下,显示的数据与数据库中存储的一致,ok,我们的mybatis就算是引入成功了。

初学者idea web项目搭建之路(五) mybatis

最后,贴一下现在我们的项目结构。

初学者idea web项目搭建之路(五) mybatis


2019.3.12日补充

[email protected]注解,如下:当有多个形参时,需要用该标签帮助myBatista锁定属性。

ps:可将形参设置成对应实体类简化操作。需要在Mapper.xml做映射操作(resultmap标签)(后续整理)

public interface UserDao {
    //检查账号密码是否正确
    boolean checkLogin(@Param("account")String account, @Param("password")String password);
    //检查该账号是否被注册
    boolean checkRegister(String account);
}

2.特殊使用,使用count统计数量配合boolean可实现返回true或者false的效果。

<!--通过返回值的数量判断返回true还是false,多个标识时,在dao中需要用@Param标签标识-->
    <select id="checkLogin" parameterType="String" resultType="boolean">
    select count(id)from user where account = #{account}and password= #{password}
  </select>

3.直接向项目中引入mybatis代码自动生成插件需谨慎,反正我是中招了,导致项目启动不了,可能原因,某个地方的配置gg了,也可能是某个<select>标签内的id标错了,总之这样容易产生很多问题。推荐用法,建一个专门的项目,生成后再复制过去,(刚刚问了下我的同学,是的,好像都是这样做的),每次新项目只要改下配置文件,和数据库表映射就ok了。(后续整理)

4.Dao层中的返回值设置。mybatis数据库操作的返回值

insert:返回值是:新插入行的主键(primary key);需要包含<selectKey>语句,才会返回主键,否则返回值为null。 
update/delete:返回值是:更新或删除的行数;无需指明resultClass;但如果有约束异常而删除失败,只能去捕捉异常。 
queryForObject:返回的是:一个实例对象或null;需要包含<select>语句,并且指明resultMap; 
queryForList:返回的是:实例对象的列表;需要包含<select>语句,并且指明resultMap; 

如下,insert操作,返回值设定为int用来匹配对应主键。

 //返回值是插入操作的主键
    int insertUser(UserEntity userEntity);

2019.3.19日补充

1.实际中使用mybatis很容易出现mapping.xml中id重复,或者与dao中方法名不一致的问题,这些都会导致项目启动失败。

2.使用resultmap。

 <resultMap id="BaseResultMap" type="org.ironman.ticketsellingsystem.entity.UserEntity">
        <id column="id" property="id" jdbcType="INTEGER"/>
        <result column="account" property="account" jdbcType="CHAR"/>
        <result column="password" property="password" jdbcType="CHAR"/>
        <result column="name" property="name" jdbcType="VARCHAR"/>
        <result column="age" property="age" jdbcType="INTEGER"/>
        <result column="id_card" property="idCard" jdbcType="INTEGER"/>
        <result column="sex" property="sex" jdbcType="VARCHAR"/>
        <result column="phone" property="phone" jdbcType="VARCHAR"/>
        <result column="type" property="type" jdbcType="VARCHAR"/>
        <result column="emal" property="emal" jdbcType="CHAR"/>
        <result column="state" property="state" jdbcType="VARCHAR"/>
    </resultMap>

id:标识

type:数据库做映射的对应实体类。

column:数据库中的列名。

property:实体类中的属性名。

jdbcType:数据库的数据类型

使用如下,通过resultMap指定对应的映射,便可以将数据库返回的结果存放到指定的对象中去了。

<select id="selectUser" parameterType="int" resultMap="BaseResultMap">
    select * from user where id= #{id}
  </select>

ps:若是在数据库操作中,未指定resultMap,而是使用的resultType。则实体类属性名需要与数据库列名完全一致才能取值成功,或者使用别名亦可。

2019.3.26日补充

当数据库使用了date 等时间格式的数据,我们需要在对应的实体类中做对应配置。

初学者idea web项目搭建之路(五) mybatis

@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
    private Date trainTime;

@DateTimeFormat:指明时间格式,意料之外的是使用如下代码指定格式会无法查出数据。原因不详。

@DateTimeFormat(pattern = "yyyy-MM-dd")

2019.3.27日补充

resultMap resultType 标签中都是指定数据类型,而不是集合类,哪怕dao中设置的参数为集合类,我们仍然是设定他集合类存的数据类型。