Mybatis简介
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
ORM介绍
对象关系映射(Object Relational Mapping,简称ORM)是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中。本质上就是将数据从一种形式转换到另外一种形式。 这也同时暗示着额外的执行开销;然而,如果ORM作为一种中间件实现,则会有很多机会做优化,而这些在手写的持久层并不存在。 更重要的是用于控制转换的元数据需要提供和管理;但是同样,这些花费要比维护手写的方案要少;而且就算是遵守ODMG规范的对象数据库依然需要类级别的元数据。

数据库的表(table) --> 类(class)记录(record,行数据)--> 对象(object)字段(field)--> 对象的属性(attribute)
实际应用
实际应用中即在关系型数据库和业务实体对象之间作一个映射,这样,我们在具体的操作业务对象的时候,就不需要再去和复杂的SQL语句打交道,只要像平时操作对象一样操作它就可以了。
ORM框架就是用于实现ORM技术的程序。
常见的ORM框架有:Hibernate、TopLink、Castor JDO、Apache OJB等。
Java中ORM的原理: 先说ORM的实现原理,其实,要实现JavaBean的属性到数据库表的字段的映射,任何ORM框架不外乎是读某个配置文件把JavaBean的属 性和数据库表的字段自动关联起来,当从数据库Query时,自动把字段的值塞进JavaBean的对应属性里,当做INSERT或UPDATE时,自动把 JavaBean的属性值绑定到SQL语句中。
一个简单的映射例子(hibernate),我们定义User对象和数据库中user表之间的关联,user表中只有两列:id和name:
<hibernate-mapping>
<class name="sample.orm.hibernate.User" table="user" catalog="test">
<id name="userID" type="java.lang.Integer">
<column name="id" />
<generator class="assigned" />
</id>
<property name="userName" type="java.lang.String">
<column name="name" />
</property>
</class>
</hibernate-mapping>
即使我不了解MySQL也没有多大问题。掌握了Mybatis再看JDBC也很简单。
集成MyBatis
- 添加Spring Web依赖
- 添加MyBatis Framework依赖
- 添加MySQL Driver依赖
如果使用 Maven 来构建项目,则需将下面的依赖代码置于 pom.xml 文件中:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
配置MySQL连接
在Spring Boot工程的application.properties文件里添加:
spring.datasource.url=jdbc:mysql://mysql数据库地址:数据库端口/数据库名称?serverTimezone=GMT%2B8
spring.datasource.username=用户名
spring.datasource.password=密码
serverTimezone=GMT%2B8这个参数设置数据库时区为中国区域。不然使用默认时区和我们当地时间相差八小时。
实战评论组件概要设计
概要设计
软件工程设计角度:先对产品做模型设计,然后再看数据库的设计。
三大功能点:
- 用户登录
- 写评论
- 回复评论
抽象对象,设计领域模型,我们能够得出需要一个用户模型和评论模型。
这里一个难点就是回复评论这个动作,我们的需要设计一个Tree结构才能瞒住数据存储。当多个人评论A的时候,我们可以吧回复的评论当做是A的子,这样就形成了树结构。
数据库设计
user、comment表

user表
comment表
drop table if exists user;
create table user (
`id` bigint not null primary key auto_increment,
`user_name` varchar(20) not null,
`pwd` varchar(32) not null,
`nick_name` varchar(20),
`avator` varchar(20),
`gmt_created` datetime not null,
`gmt_modified` datetime not null
);
drop table if exists comment;
create table comment (
`id` bigint not null primary key auto_increment,
`ref_id` varchar(32) not null,
`user_id` bigint not null,
`contentt` varchar(1000) not null,
`parent_id` bigint,
`gmt_created` datetime not null,
`gmt_modified` datetime not null
);
insert into user (user_name,pwd,nick_name,gmt_created,gmt_modified) values(
'admin','123','管理员',now(),now()
)
MyBatis映射对象
DO对象规则
所有的ORM框架都需要一个Java对象来映射数据库的表,并且一一对应,我们把这类对象成为DO对象,名称规范:表名+DO
user表——>UserDO
comment——>CommentDO
ykd_user——>UserDO(常用)/YkdUserDO
DO对象包规则
DO对象放在xxx.xxx.dataobject包下,DO(data object)。com.youkeda.comment——>com.youkeda.commentdataobject
DO对象数据类型
创建DO对象
UserDO对象
package com.youkeda.comment.dataobject;
import java.time.LocalDateTime;
public class UserDO {
private long id;
private String userName;
private String pwd;
private String nickName;
private String avatar;
private LocalDateTime gmtCreated;
private LocalDateTime gmtModified;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public LocalDateTime getGmtCreated() {
return gmtCreated;
}
public void setGmtCreated(LocalDateTime gmtCreated) {
this.gmtCreated = gmtCreated;
}
public LocalDateTime getGmtModified() {
return gmtModified;
}
public void setGmtModified(LocalDateTime gmtModified) {
this.gmtModified = gmtModified;
}
}
MyBatis DAO
DAO层—数据层的服务,DAO层包含对数据库操作的接口和实现类。
DAO层
com.youkeda.comment.dao
定义DAO接口
package com.lzx.comment.dao;
import org.apache.ibatis.annotations.Mapper;
/**
* @InterfaceName UserDAO
* @Author 刘正星
* @Date 2020/7/12 13:33
**/
@Mapper
public interface UserDAO {
}
查询
package com.lzx.comment.dao;
import org.apache.ibatis.annotations.Mapper;
/**
* @InterfaceName UserDAO
* @Author 刘正星
* @Date 2020/7/12 13:33
**/
@Mapper
public interface UserDAO {
@Select("SELECT id,user_name as userName,pwd,nick_name as nickName,avatar,gmt_created as gmtCreated,gmt_modified as gmtModified FROM user")
List<UserDO> findAll();
}
@Select注解
利用 as 构建user_name 与 userName之间的映射。
插入
@Insert注解,插执行SQL语句插入的时候,会返回插入行数。返回值设置为int。
import UserDO;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface UserDAO {
@Insert("INSERT INTO user (user_name, pwd, nick_name,avatar,gmt_created,gmt_modified) VALUES(#{userName}, #{pwd}, #{nickName}, #{avatar},now(),now())")
int insert(UserDO userDO);
@Select("SELECT id,user_name as userName,pwd,nick_name as nickName,avatar,gmt_created as gmtCreated,gmt_modified as gmtModified FROM user")
List<UserDO> findAll();
}
我们把 value 的值换成了 #{变量名} 这是MyBatis 获取动态值得方式。也就是执行userDO.getUserName()。
查看主键值
在@Insert注解上添加一个@Options主键。
@Options(useGeneratedKeys = true, keyColumn = "id", keyProperty = "id")
Options注解有三个参数
- userGeneratedKeys:设置为ture,代表允许使用自增主键
- keyColumn:设置主键字段名称,一般是id
keyProperty:设置DO模型的主键字段,一般都是id
修改
/** * 更新 * @param commentDO * @return */ @Update("UPDATE comment set user_id = #{userId},content = #{content},gmt_modified = now() where id =#{id}") int update(CommentDO commentDO);约定:同步修改gmtModified字段。这样就可以查看修改时间了
删除
MyBatis除了可以接受对象,还可以接受普通参数,如String ,int等。
@Param('key')这个用法在以后运用的还是比较多的,因为它可以实现自定义上下文参数,非常实用和方便@Delete("delete from user where id=#{id}") int delete(@Param("id") long id);简单查询
通过用户名来查找:
select * from user where user_name=? limit 1设计接口方法: ```java public interface UserDAO {
@Select(“select id,user_name as userName,pwd,nick_name as nickName,avatar,gmt_created as gmtCreated,gmt_modified as gmtModified from user where user_name=#{userName} limit 1”) UserDO findByUserName(@Param(“userName”) String name);
}
<a name="R7a82"></a>
## API测试
```java
package com.lzx.comment.control;
import com.lzx.comment.dao.UserDAO;
import com.lzx.comment.dataobject.UserDO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @ClassName UserController
* @Author 刘正星
* @Date 2020/7/12 13:35
**/
@Controller
public class UserController {
@Autowired
private UserDAO userDAO;
@GetMapping("/users")
@ResponseBody
private List<UserDO> getAll(){
return userDAO.findAll();
}
@PostMapping("/user")
public UserDO save(@RequestBody UserDO userDO){
userDAO.insert(userDO);
return userDO;
}
@PostMapping("/user/update")
@ResponseBody
public UserDO update(@RequestBody UserDO userDO){
userDAO.update(userDO);
return userDO;
}
@GetMapping("/user/del")
@ResponseBody
public boolean delete(@RequestParam("id") Long id) {
return userDAO.delete(id) > 0;
}
@GetMapping("/user/findByUserName")
@ResponseBody
public UserDO findByUserName(@RequestParam("userName") String userName) {
return userDAO.findByUserName(userName);
}
}
package com.lzx.comment.control;
import com.lzx.comment.dao.CommentDAO;
import com.lzx.comment.dataobject.CommentDO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @ClassName CommentController
* @Author 刘正星
* @Date 2020/7/12 13:36
**/
@Controller
public class CommentController {
@Autowired
private CommentDAO commentDAO;
@GetMapping("/comments")
@ResponseBody
public List<CommentDO> getAll(){
return commentDAO.findAll();
}
@PostMapping("/comment")
@ResponseBody
public CommentDO save(@RequestBody CommentDO commentDO){
commentDAO.insert(commentDO);
return commentDO;
}
@PostMapping("/comment/update")
@ResponseBody
public CommentDO update(@RequestBody CommentDO commentDO){
commentDAO.update(commentDO);
return commentDO;
}
@GetMapping("/comment/del")
@ResponseBody
public boolean delete(@RequestParam("id")long id){
return commentDAO.delete(id)>0;
}
@GetMapping("/comment/findByRefId")
@ResponseBody
public List<CommentDO> findByRefId(@RequestParam("refId")String refId){
return commentDAO.findByRefId(refId);
}
}


