一、浅析mybatis
前段时间学习了jdbc、mybatis两个框架,又做了个不大不小的项目,就来这给大家班门弄斧总结下,如有不足还请温柔指正。
什么是mybatis? 官网给的答案是这样的https://mybatis.org/mybatis-3/zh/index.html
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。
说人话就是连接数据库和java的工具,他有很强的可控性,体现在它操作数据库、存储数据的sql语句都是由程序员自己写在xml文件里,再将xml文件映射到对应的Mapper接口。
二、项目结构(以下内容均是在有了数据库的前提下操作)
这个就不用太多文字来描述了,直接上图
三、配置pom.xml
这个文件里面的内容都是各种依赖,例如:log4j,sql,junit等等。(根据项目所需自行添加,这里展示的是我用到的)
上代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>uolab</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.0</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.200</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-runner</artifactId>
<version>1.5.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13-rc-2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>6</source>
<target>6</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
四、编写mybatis工具类(我这里叫DBUtil)
mybatis工具类的主要任务就是使用SqlSessionFactoryBuilder创建SqlSessionFactory。使用SqlSessionFactory创建SqlSession。SqlSession可以通过Sql Mapper.class进行数据库操作,或者直接使用SqlSession的方法输入SqlMapper.方法()进行数据库操作,使用完要关闭。
上代码
package com.ychs.util;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.log4j.Logger;
import java.io.InputStream;
public class DBUtil {
/**
* 单元测试用
**/
private SqlSession session;
private static boolean closeFlag = false;
// 创建一个Log4j的对象
private Logger logger = Logger.getLogger(DBUtil.class);
// 工具类 单例模式 23种设计模式 只有一个实例 单例模式
// 单例模式 不让你new 对象 直接私有
/**
* @Author hp
* @Description
* 单例对象,饿汉模式 系统加载内存时,已经初始化了
* @Date 15:59 2021/5/18
* @Param
* @return
**/
// private static MyDBUtil dbUtil = new MyDBUtil();
/**
* @Author hp
* @Description
* 懒汉模式,单例对象
* @Date 16:03 2021/5/18
* @Param
* @return
**/
private static DBUtil dbUtil;
private SqlSessionFactory factory;
/**
* @Author hp
* @Description
* 私有化构造方法 是为了单例做准备
* @Date 15:56 2021/5/18
* @Param []
* @return
**/
private DBUtil(){
InputStream is = null;
try {
is = Resources.getResourceAsStream("mybatis-cfg.xml");
// logger.debug("is = " + is);
// logger.info("info is = " + is);
// logger.error("error is = "+ is);
factory = new SqlSessionFactoryBuilder().build(is);
} catch (Exception e) {
// logger.error("初始化时出错了", e);
e.printStackTrace();
}
}
/**
* @Author hp
* @Description
* 单例模式对外提供出口,返回自身单例对象
* @Date 15:58 2021/5/18
* @Param []
* @return com.ychs.DBUtil.MyDBUtil
**/
public static DBUtil getInstance(){
// 饿汉模式
// return dbUtil;
if (dbUtil == null){
// 不能再懒了,此时必须要初始化
dbUtil = new DBUtil();
}
return dbUtil;
}
// 静态特别占用资源 释放不了
// MyDBUtil.getInstance().getSqlSession();
/**
* 获取session会话,当数据库链接异常时,会返回null对象
* @return sesson 会话
**/
public SqlSession getSqlSession(){
// if (factory != null){
// return factory.openSession();
// }
// return null;
// h2单元测试
if (session == null){
session = factory.openSession();
}
return session;
}
public static void close(SqlSession session){
if (closeFlag){
session.close();
}
}
}
五、entity层(实体类 这一层不同的人叫法不同)
在日常的Java项目开发中,entity(实体类)是必不可少的,它们一般都有很多的属性,并有相应的setter和getter方法。entity(实体类)的作用一般是和数据表做映射。
说人话就是把数据库里的每个表写成一个实力类,表里的每个字段原封不动(为了后期方便,尽量同名)的写成类属性。
上代码
package com.ychs.entity;
import java.util.List;
public class User {
/**
* id
*/
private int id;
/**
* 性别
*/
private int sex;
/**
* 院系
*/
private College college;
/**
* 专业
*/
private Major major;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 角色
*/
private Role role;
/**
* 状态
*/
private String state;
/**
* 真实姓名
*/
private String name;
/**
* 年级
*/
private int grade;
/**
* 班级
*/
private String clazz;
/**
* 职务
*/
private String schoolJob;
/**
* 电话
*/
private String phone;
/**
* QQ
*/
private String QQ;
/**
* 备注
*/
private String remark;
public int getId() {
return id;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public void setId(int id) {
this.id = id;
}
public College getCollege() {
return college;
}
public void setCollege(College college) {
this.college = college;
}
public Major getMajor() {
return major;
}
public void setMajor(Major major) {
this.major = major;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getGrade() {
return grade;
}
public void setGrade(int grade) {
this.grade = grade;
}
public String getClazz() {
return clazz;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
public String getSchoolJob() {
return schoolJob;
}
public void setSchoolJob(String schoolJob) {
this.schoolJob = schoolJob;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getQQ() {
return QQ;
}
public void setQQ(String QQ) {
this.QQ = QQ;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
"sex=" + sex +
", college=" + college +
", major=" + major +
", username='" + username + '\'' +
", password='" + password + '\'' +
", role='" + role + '\'' +
", state='" + state + '\'' +
", name='" + name + '\'' +
", grade=" + grade +
", clazz='" + clazz + '\'' +
", school_job='" + schoolJob + '\'' +
", phone='" + phone + '\'' +
", QQ='" + QQ + '\'' +
", remark='" + remark + '\'' +
'}';
}
}
六、创建Dao层接口
Dao接口负责定义service层(服务层)要用到的方法(比如增删改查)
上代码
package com.ychs.dao;
import java.util.List;
import java.util.Map;
public interface BaseMapper<T> {
// insert update delete select selectById
/**
* 插入记录
* @param t
* @return 影响的行数
*/
int insert(T t);
/**
* 更新记录
* @param t
* @return 影响的行数
*/
int update(T t);
/**
* 删除记录
* @param
* @return 影响的行数
*/
int delete(int id);
/**
* 查询单个记录
* @param id 主键
* @return 对象
*/
T selectById(int id);
/**
* 返回满足条件的记录
* @param conditions 查询条件
* @return 多条记录
*/
List<T> selectByCondition(Map<String,Object> conditions);
}
七、创建Mapper.xml映射文件(有些人选择把映射文件放入resource文件夹,这里我把它也放在Dao层)
Mapper.xml文件是mybatis项目的核心
最上面一段复制官网https://mybatis.org/mybatis-3/zh/getting-started.html “ 探究以映射的sql语句 ” 下的第一段代码。然后把他的sqlect标签里面的内容换成自己的项目功能所需的sql代码
上代码
<?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="com.ychs.dao.CollegeMapper">
<!--parameterType可以省略-->
<!--#{对象的属性名}-->
<!--添加院系-->
<insert id="insert" parameterType="com.ychs.entity.College">
insert into college (code, name, updatetime)
values (#{code}, #{name}, sysdate())
</insert>
<!--按照条件查询-->
<select id="selectByCondition" resultType="College" parameterType="map">
select name ,code from college
<where>
<if test="id!=null">
and id = #{id}
</if>
<if test="name!=null">
and name like '%${name}%'
</if>
<if test="code!=null">
and code = #{code}
</if>
</where>
</select>
<!--删除院系-->
<delete id="delete">
delete
from college
where id = #{id}
</delete>
<!--修改院系-->
<update id="update" parameterType="college">
update college
set code=#{code},
name=#{name},
updatetime=sysdate()
where id=#{id}
</update>
<!--按照id查询-->
<select id="selectById" resultType="college">
select *
from college
where id = #{id}
</select>
</mapper>
八、service层(业务逻辑层)
service层是一个相对独立的功能模块,主要负责业务逻辑应用设计。我们可以在应用中调用service接口进行业务处理。service层业务实现,具体调用到已经定义的Dao的接口,封装service层的业务逻辑有利于通用的业务逻辑的独立性和重复利用性 。
说人话就是写项目需要的方法(例如增删改查)
上代码
package com.ychs.service;
import com.ychs.dao.UserMapper;
import com.ychs.entity.User;
import com.ychs.util.Constants;
import com.ychs.util.DBUtil;
import org.apache.ibatis.session.SqlSession;
import java.util.List;
import java.util.Map;
public class UserService implements IBaseService<User> {
@Override
public boolean add(User user) {
SqlSession session = DBUtil.getInstance().getSqlSession();
UserMapper mapper = session.getMapper(UserMapper.class);
int result = mapper.insert(user);
session.commit();
DBUtil.close(session);
return result == Constants.UPDATE_SUCCESS;
}
@Override
public boolean modify(User user) {
SqlSession session = DBUtil.getInstance().getSqlSession();
UserMapper mapper = session.getMapper(UserMapper.class);
int result = mapper.update(user);
session.commit();
DBUtil.close(session);
return result == Constants.UPDATE_SUCCESS;
}
@Override
public User searchById(int id) {
SqlSession session = DBUtil.getInstance().getSqlSession();
UserMapper mapper = session.getMapper(UserMapper.class);
User result = mapper.selectById(id);
DBUtil.close(session);
return result;
}
@Override
public List<User> search(Map map) {
SqlSession session = DBUtil.getInstance().getSqlSession();
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> result = mapper.selectByCondition(map);
DBUtil.close(session);
return result;
}
@Override
public boolean remove(int id) {
SqlSession session = DBUtil.getInstance().getSqlSession();
UserMapper mapper = session.getMapper(UserMapper.class);
int result = mapper.delete(id);
session.commit();
DBUtil.close(session);
return result==Constants.UPDATE_SUCCESS;
}
}
九、Test(测试)
选中需要测试的类名用快捷键(shift+ctrl+T)创建Test测试文件(千万不要手动创建),选择对应的junit版本,现在一般都是用junit4或者junit5,然后把要测试的类都选中点确定,
好了,现在只差数据了。我们可以在初始化数据库表的时候将测试数据插入,但相对于每一个测试来说,数据不够细,且这些数据不好维护。我更倾向于在测试类中初始化相应的数据。具体的用法这些就得自己去看了,这里给个简单的例子,上代码
package com.ychs.service;
import com.ychs.entity.College;
import com.ychs.entity.Major;
import com.ychs.entity.Role;
import com.ychs.entity.User;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.TestMethodOrder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import static org.junit.jupiter.api.Assertions.*;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class UserServiceTest {
UserService service = new UserService();
Logger logger = Logger.getLogger("UserServiceTest.class");
@org.junit.jupiter.api.Test
@Order(1)
void add() {
User user = new User();
College college = new College();
Major major = new Major();
college.setId(1);
college.setName("北京大学");
college.setCode(0351);
user.setCollege(college);
major.setId(1);
user.setId(1);
major.setName("软件工程");
major.setCode(100);
user.setClazz("562");
user.setGrade(2018);
user.setName("李大侠");
user.setUsername("秃头");
user.setSex(0);
user.setPassword("123456");
user.setPhone("187323");
user.setQQ("2946799");
Role role = new Role();
role.setId(1);
user.setRole(role);
user.setState("在线");
user.setSchoolJob("班长");
user.setRemark("备注");
boolean result = service.add(user);
assertTrue(result);
}
@org.junit.jupiter.api.Test
@Order(2)
void modify() {
User user = new User();
College college = new College();
college.setId(1);
college.setName("清华大学");
college.setCode(0351);
Major major = new Major();
major.setId(1);
major.setName("软件工程");
major.setCode(100);
user.setId(1);
user.setCollege(college);
user.setMajor(major);
user.setClazz("561");
user.setGrade(2020);
user.setName("光头");
user.setSex(1);
user.setUsername("胖子");
user.setPassword("123456");
user.setPhone("10088");
user.setQQ("294629");
Role role = new Role();
role.setId(1);
user.setRole(role);
user.setState("在线");
user.setSchoolJob("班长");
user.setRemark("备注");
boolean result = service.modify(user);
assertTrue(result);
}
@org.junit.jupiter.api.Test
@Order(3)
void selectById() {
User user = service.searchById(1);
assertNotNull(user);
}
@org.junit.jupiter.api.Test
@Order(4)
void search() {
Map map = new HashMap();
map.put("id","1");
map.put("grade","2020");
map.put("name","大黄");
List<User> users = service.search(map);
assertNotNull(users);
}
/*@org.junit.jupiter.api.Test
@Order(5)
void remove() {
boolean result = service.remove(1);
assertTrue(result);
}*/
}