Mybatis是Apache的一个Java开源项目,是一个支持动态Sql语句的持久层框架。Mybatis可以将Sql语句配置在XML文件中,避免将Sql语句硬编码在Java类中。与JDBC相比: 1)Mybatis通过参数映射方式,可以将参数灵活的配置在SQL语句中的配置文件中,避免在Java类中配置参数(JDBC) 2)Mybatis通过输出映射机制,将结果集的检索自动映射成相应的Java对象,避免对结果集手工检索(JDBC) 3)Mybatis可以通过Xml配置文件对数据库连接进行管理
2. mybatis基本构成
SqlSessionFactoryBuilder: 根据配置信息生成SqlSessionFactory SqlSessionFactory: 用于生成SqlSession SqlSession: SqlSession是MyBatis的关键对象,通过这个接口可以操作命令,管理事务等 SqlMapper:MyBatis的设计组件,有java接口和xml文件构成。需要给出对应的sql映射和映射规则
两者均为ORM框架,但也有一些不同
mybatis | hibernate |
---|---|
轻量级 | 重量级 |
半自动化 | 全自动化 |
sql | hql(但也可以使用sql,但违背了hibernate的初衷) |
扩展性、迁移性比较差 | 无缝移植 |
1) 使用maven新建一个web工程 2) idea在创建web工程时不会自动创建java,resources,test等目录,可以手动创建
3)通过pom.xml添加必要的依赖,直接将相关依赖考到项目中的pom.xml文件即可。
4.0.0
org.example
deomMybatis
1.0-SNAPSHOT
war
deomMybatis Maven Webapp
http://www.example.com
UTF-8
1.8
1.8
8.0.29
3.5.9
5.3.18
junit
junit
4.13.1
test
org.springframework
spring-context
${spring-version}
org.springframework
spring-web
${spring-version}
org.springframework
spring-tx
${spring-version}
org.springframework
spring-aop
${spring-version}
org.springframework
spring-test
${spring-version}
org.springframework
spring-jdbc
${spring-version}
org.springframework
spring-webmvc
${spring-version}
org.springframework
spring-aspects
${spring-version}
org.mybatis
mybatis-spring
2.0.6
org.apache.commons
commons-dbcp2
2.9.0
org.apache.commons
commons-pool2
2.11.1
mysql
mysql-connector-java
${mysql-version}
org.mybatis
mybatis
${mybatis-version}
com.belerweb
pinyin4j
2.5.1
org.projectlombok
lombok
1.18.22
provided
org.slf4j
slf4j-api
1.7.36
ch.qos.logback
logback-classic
1.2.10
javax.servlet
javax.servlet-api
3.1.0
provided
com.github.pagehelper
pagehelper
5.1.2
jstl
jstl
1.2
taglibs
standard
1.1.2
deomMybatis
org.apache.maven.plugins
maven-clean-plugin
3.1.0
org.apache.maven.plugins
maven-resources-plugin
3.0.2
org.apache.maven.plugins
maven-compiler-plugin
3.8.0
org.apache.maven.plugins
maven-surefire-plugin
2.22.1
org.apache.maven.plugins
maven-war-plugin
3.2.2
org.apache.maven.plugins
maven-install-plugin
2.5.2
org.apache.maven.plugins
maven-deploy-plugin
2.8.2
org.apache.maven.plugins
maven-surefire-plugin
true
4)将mybatis 配置到spring中的 核心配置文件(applicationContext-base.xml),jdbc.properties 连接参数, logback.xml日志考到项目的resources目录下,并修改数据库的连接。
applicationContext-base.xml spring核心配置文件
helperDialect=mysql
jdbc.properties mysql 8.0 连接配置文件
driver.name=com.mysql.cj.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf-8&allowPublicKeyRetrieval=true
db.user=root
db.password=123456
logback.xml 配置日志文件
%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
${LOG_HOME}/${LOG_NAME}.%d{yyyy-MM-dd}.log
30
%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
10MB
5) 在src/main/resources目录下创建mapper用于方式mybatis的映射文件
6)创建包的目录结构,如下图所示:
7)ssh2与ssm的对应关系
ssh2 | ssm |
---|---|
action | controller |
service | service |
dao | mapper |
IXxxDao.java | XxxMapper |
XxxDao.java | XxxMapper.xml |
entity | model |
Xxx.java | Xxx.java |
Xxx.hbm.xml |
8)编写model,即存放数据的对象,在ssh2时叫做entity。
这里就可以看到 我们所用的lombok的强大的 @Data 会自动生成 get set 与tostring 等等。。。。
使用lombok需要有的插件
9)mapper编写(相当于dao)。
编写之前我们需下载一个插件方便编写mybatis 如下图
10)在目录结构中加入一个mapper包,在该包中创建一个TestMapper接口
创建好接口后 ----可直接使用插件生成 mybatis的xml配置文件
注意 :第一次创建的时候会提示你选择地址 我们直接选择 resources 中我们创建的mapper文件
1.mapper中定义的接口
package com.zking.mybatis01.mapper;
import com.zking.mybatis01.dto.StudentDto;
import com.zking.mybatis01.model.Student;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository("studentMapper")
public interface IStudentMapper {
/**
* 查询所有学生
* @param stu 根据姓名 模糊查询
* @return 返回 学生集合
*/
public List listStudent(Student stu);
/**
* 增加学生
* @param stu 学生实体
*/
public Integer addStudent(Student stu);
/**
* 修改学生信息
* @param upd
* @return
*/
public Integer updStudent(Student upd);
/**
* 根据学生id 进行删除
* @param stu
* @return
*/
Integer delStudent(Student stu);
/**
* 根据 用户多个id查询
* @return
*/
List listStudentByid(StudentDto dto);
}
注意:在xml中注释的方法要在对应的java接口中注释掉,(注释掉只是为了少写点代码,尽快测试)
注:#{} 与 ${} 的区别 #{ }是预编译处理,MyBatis在处理#{ }时,它会将sql中的#{ }替换为?,然后调用PreparedStatement的set方法来赋值,传入字符串后,会在值两边加上单引号,如上面的值 “4,44,514”就会变成“ ‘4,44,514’ ”
${ }是字符串替换, MyBatis在处理${ }时,它会将sql中的${ }替换为变量的值,传入的数据不会加两边加上单引号。
使用${ }会导致sql注入,不利于系统的安全性!
SQL注入:就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。常见的有匿名登录(在登录框输入恶意的字符串)、借助异常获取数据库信息等
2.如数据库与实体的属性名不一致 需要配置映射关系 如图:
2.1 .我们配置好的 增删改查
Insert into t_student (sname,birthday,ssex)
values (#{sname},#{birthday},#{ssex})
update t_student
sname = #{sname},
birthday = #{birthday},
ssex = #{ssex,jdbcType=NUMERIC}
sid = #{sid}
delete from t_student
sid = #{sid}
3.接下来我们编写service 事务层
定义我们的service接口 ↓
package com.zking.mybatis01.service;
import com.zking.mybatis01.dto.StudentDto;
import com.zking.mybatis01.model.Student;
import com.zking.mybatis01.utils.PageBean;
import java.util.List;
public interface IStudentService {
/**
* 查询所有学生信息
* @param stu 模糊查询
* @return 学生集合
*/
List listStudentpaging(Student stu , PageBean pge);
/**
* 增加学生
* @param stu 学生实体
*/
Integer addStudent(Student stu);
/**
* 修改学生信息
* @param upd
* @return
*/
public Integer updStudent(Student upd);
/**
* 根据学生id 进行删除
* @param stu
* @return
*/
Integer delStudent(Student stu);
/**
* 根据 用户多个id查询
* @return
*/
List listStudentByid(StudentDto dto );
}
定义实现类
package com.zking.mybatis01.service;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zking.mybatis01.dto.StudentDto;
import com.zking.mybatis01.interfaces.Paging;
import com.zking.mybatis01.mapper.IStudentMapper;
import com.zking.mybatis01.model.Student;
import com.zking.mybatis01.utils.PageBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class StudentServiceImpl implements IStudentService {
//类型判断 注入
@Autowired
private IStudentMapper stu;
@Override
public List listStudentpaging(Student stu, PageBean pge) {
return this.stu.listStudent(stu);
}
@Override
public Integer addStudent(Student stu) {
return this.stu.addStudent(stu);
}
@Override
public Integer updStudent(Student upd) {
return this.stu.updStudent(upd);
}
@Override
public Integer delStudent(Student stu) {
return this.stu.delStudent(stu);
}
@Override
public List listStudentByid(StudentDto dto) {
return this.stu.listStudentByid(dto);
}
}
编写测试用例 测试功能
部分测试
package com.zking.mybatis01.service;
import com.zking.mybatis01.dto.StudentDto;
import com.zking.mybatis01.model.Student;
import com.zking.mybatis01.utils.PageBean;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
//帮我们去生成spring 上下文对象
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath*:applicationContext*.xml"})
public class StudentServiceImplTest {
@Autowired
private IStudentService studentService;
@Test
public void listStudent() {
Student st=new Student();
st.setBirthday(new Date());
st.setSname("小黑");
st.setSsex(1);
/*List students = studentService.listStudent(st);
students.forEach(t->System.out.println(t));*/
Integer i= studentService.addStudent(st);
System.out.println(i);
}
@Test
public void updStudent(){
Student st=new Student();
st.setSid(1);
st.setBirthday(new Date());
st.setSname("小名");
st.setSsex(1);
Integer integer = studentService.updStudent(st);
System.out.println(integer);
}
@Test
public void delStudent(){
Student st=new Student();
st.setSid(18);
Integer integer = studentService.delStudent(st);
System.out.println(integer);
}
@Test
public void listStudentByid(){
StudentDto studentDto = new StudentDto();
studentDto.setListSid(Arrays.asList(1,2,3,5,6));
List students = studentService.listStudentByid(studentDto);
students.forEach(System.out::println);
}
}
引入pagehelper 包 如果复制了上方的pom的 可不需要加入
com.github.pagehelper
pagehelper
5.1.2
1.编写分页实体便于分页
package com.zking.mybatis01.utils;
import com.mysql.cj.util.StringUtils;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
public class PageBean {
/**
* 页码
*/
private int page = 1;
/**
* 每页显示的记录数
*/
private int rows = 10;
/**
* 总记录数
*/
private int total = 0;
/**
* 是否分页
*/
private boolean pagination = true;
/**
* 记录查询的url,以便于点击分页时再次使用
*/
private String url;
/**
* 存放请求参数,用于生成隐藏域中的元素
*/
private Map parameterMap;
/**
* 根据传入的Request初始化分页对象
* @param request
*/
public void setRequest(HttpServletRequest request) {
if(!StringUtils.isNullOrEmpty(request.getParameter("page"))) {
this.page = Integer.valueOf(request.getParameter("page"));
}
if(!StringUtils.isNullOrEmpty(request.getParameter("rows"))) {
this.rows = Integer.valueOf(request.getParameter("rows"));
}
if(!StringUtils.isNullOrEmpty(request.getParameter("pagination"))) {
this.pagination = Boolean.valueOf(request.getParameter("pagination"));
}
this.url = request.getRequestURI();
this.parameterMap = request.getParameterMap();
request.setAttribute("pageBean", this);
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getRows() {
return rows;
}
public void setRows(int rows) {
this.rows = rows;
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public boolean isPagination() {
return pagination;
}
public void setPagination(boolean pagination) {
this.pagination = pagination;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Map getParameterMap() {
return parameterMap;
}
public void setParameterMap(Map parameterMap) {
this.parameterMap = parameterMap;
}
//计算起始页码
public int getStartIndex() {
return (this.page - 1) * this.rows;
}
//获取总页数
public int getTotalPage() {
if (this.getTotal() % this.rows == 0) {
return this.getTotal() / this.rows;
} else {
return this.getTotal() / this.rows + 1;
}
}
//上一页
public int getPreviousPage() {
return this.page - 1 > 0 ? this.page - 1 : 1;
}
//下一页
public int getNextPage() {
return this.page + 1 > getTotalPage() ? getTotalPage() : this.page + 1;
}
}
2.在aop包中定义分页切面
package com.zking.mybatis01.aop;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zking.mybatis01.utils.PageBean;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@Aspect
public class PaginAop {
//环绕通知 自定义注解 分辨是否调用
@Around("@annotation(com.zking.mybatis01.interfaces.Paging)")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
//获取目标方法的所有参数
Object[] args = joinPoint.getArgs();
PageBean pag =null;
for (Object arg : args) {
if(arg instanceof PageBean){
pag=(PageBean) arg;
if(pag!=null && pag.isPagination()){
PageHelper.startPage(pag.getPage(),pag.getRows());
}
}
}
Object proceed = joinPoint.proceed();
if(pag!=null && pag.isPagination()){
PageInfo info=new PageInfo((List) proceed);
pag.setTotal((int)info.getTotal());
}
return proceed;
}
}
接下来我们就可以去使用注解了
1.我们将自定义注解标记在我们需要分页的方法上 在service中实现
2.测试用例中添加
@Test
public void listStudentPage(){
PageBean page=new PageBean();
page.setRows(3);
List students = studentService.listStudentpaging(null, page);
students.forEach(System.out::println);
}
3.运行结果