题外话:
在了解mybatis框架之前,我先说明一句,目前主流的框架技术层出不穷,每个人都有自己喜欢的技术框架,自己喜欢用就行。技术并没有高低之分,喜欢用就用,虽然目前大部分人都喜欢向新技术看齐,但是我个人觉得任何技术,都有他自己存在的意义,新的技术可以学,但旧技术我们也不能说他不行。
本文将带你使用java快速搭建一个MyBatis项目,并且实现简单的增删改查操作,动态增删改查将在本文第二篇
MyBatis框架介绍
Mybatis是一款优秀的持久层框架,它是一个基于Java语言的、开源的、轻量级的ORM框架,可以用于处理关系型数据库的操作。
Mybatis作为ORM框架,其内部封装JDBC,故而使得开发者只需要关注SQL本身,并不需要花费精力去加载驱动,创建链接,创建statement等繁琐的过程。
Mybatis的主要特点是灵活、简单、易于学习和使用。Mybatis的主要工作原理是将Java对象映射成数据库的记录,实现Java对象和数据库表之间的转换。Mybatis的核心组件包括SqlSessionFactory、SqlSession、Mapper和MappedStatement。
-
SqlSessionFactory
SqlSessionFactory是用于创建SqlSession对象的工厂类。SqlSession对象是Mybatis中最重要的核心类之一,它是一个线程安全的、非常轻量级的对象,用于执行数据库操作和管理事务。SqlSessionFactory通常通过Mybatis的配置文件进行配置,可以指定数据源、事务管理器和Mapper映射文件等信息。 -
SqlSession
SqlSession是一个线程安全的、非常轻量级的对象,用于执行数据库操作和管理事务。SqlSession提供了多种操作数据库的方法,包括查询、插入、更新和删除等,还可以设置事务的隔离级别和自动提交等。 -
Mapper
Mapper是一个Java接口,用于定义SQL语句的执行方法。Mapper接口中的方法与SQL语句是一一对应的,可以通过SqlSession的getMapper方法获取Mapper接口的实例,并调用其中的方法执行SQL语句。 -
MappedStatement
MappedStatement是一个Java对象,用于描述Mapper接口中的SQL语句和参数信息。MappedStatement包括SQL语句的ID、SQL语句的类型、输入参数和输出参数等信息。
Mybatis的主要优点是:
-
灵活性高:Mybatis的配置文件非常灵活,可以使用XML或注解进行配置,支持自定义标签和属性,可以灵活地进行SQL语句的编写和调优。
-
易于学习和使用:Mybatis的API非常简单,容易学习和使用,开发人员可以快速上手,快速实现对数据库的操作。
-
易于维护和调试:Mybatis的映射文件和Java代码是分离的,容易维护和调试,开发人员可以很方便地对SQL语句进行调优和修改,提高SQL语句的执行效率。
-
易于扩展和定制化:Mybatis的插件机制非常强大,可以对SQL语句进行拦截和修改,也可以自定义类型处理器和结果集处理器,实现对特定数据类型的处理和转换。
-
良好的性能和扩展性:Mybatis采用了基于XML的配置方式和基于Java的Mapper接口,可以实现动态SQL语句的生成和优化,同时也支持多数据源和分布式数据库的操作,具有良好的性能和扩展性。
总之,Mybatis是一款优秀的持久层框架,它具有灵活性高、易于学习和使用、易于维护和调试、易于扩展和定制化、良好的性能和扩展性等优点,被广泛应用于Java企业级应用中的数据持久化层。
我的文件目录结构:
文件目录结构摆上了,如果跟着我的步骤下来的出现问题,我觉得是你的目录结构出问题了。
简单介绍完了,开始重头戏
第一步,先拿到数据库,这里提供一个实例数据库:
create database if not exists MyBatis_stu default character set utf8 collate utf8_bin; use MyBatis_stu ;create table if not exists classinfo(cid int primary key auto_increment,cname varchar(100) not null unique comment '班级编号'
)ENGINE=InnoDB auto_increment=101 default charset=utf8 collate=utf8_bin;create table if not exists stuinfo (sid int primary key auto_increment,sname varchar(100) not null comment '学生姓名',cid int comment '所在班级编号',tel varchar(15) unique comment '联系方式',addr varchar(100) comment '家庭住址',constraint FK_stuinfo_cid foreign key(cid) references classinfo(cid)
)ENGINE=InnoDB auto_increment=101 default charset=utf8 collate=utf8_bin;
这一步,我觉得不要多说了,毕竟你学java到现在,这一步还是没看懂的话,我觉得你可以准备考虑考虑其他路了。
第二步前台条件,你要创建好一个maven项目,并导入相关依赖,别告诉我你忘记了maven工程如何创建了?
<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>com.xh</groupId><artifactId>Maven</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>Maven</name><url>http://maven.apache.org</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--导入maven链接,让maven去下载https://mvnrepository.com/artifact/mysql/mysql-connector-java --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.28</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.8</version></dependency><!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId><version>2.17.2</version><scope>test</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency></dependencies>
</project>
第二步,根据我们的数据库创建Bean类,什么?你告诉我你不知道什么事Bean类?额,你该恶补一下java了。
public class ClassInfo {private Integer cid;private String cname;public Integer getCid() {return cid;}public void setCid(Integer cid) {this.cid = cid;}public String getCname() {return cname;}public void setCname(String cname) {this.cname = cname;}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((cid == null) ? 0 : cid.hashCode());result = prime * result + ((cname == null) ? 0 : cname.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;ClassInfo other = (ClassInfo) obj;if (cid == null) {if (other.cid != null)return false;} else if (!cid.equals(other.cid))return false;if (cname == null) {if (other.cname != null)return false;} else if (!cname.equals(other.cname))return false;return true;}@Overridepublic String toString() {return "ClassInfo [cid=" + cid + ", cname=" + cname + "]";}//记得这里我的需要创建的构造方法,你可以选择跟我也可以选择不跟public ClassInfo( String cname) {this.cname = cname;}public ClassInfo(Integer cid, String cname) {super();this.cid = cid;this.cname = cname;}public ClassInfo() {super();}
}
注意,这个类,我实际上在本篇没用上,我会在下篇才用到,你可以自行选择创建或者不创建
public class StudentInfo {private Integer sid;//学生idprivate String sname;//学生姓名private Integer cid; //外键管理,类idprivate String tel; //电话号码private String addr;//地址public Integer getSid() {return sid;}public void setSid(Integer sid) {this.sid = sid;}public String getSname() {return sname;}public void setSname(String sname) {this.sname = sname;}public Integer getCid() {return cid;}public void setCid(Integer cid) {this.cid = cid;}public String getTel() {return tel;}public void setTel(String tel) {this.tel = tel;}public String getAddr() {return addr;}public void setAddr(String addr) {this.addr = addr;}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((addr == null) ? 0 : addr.hashCode());result = prime * result + ((cid == null) ? 0 : cid.hashCode());result = prime * result + ((sid == null) ? 0 : sid.hashCode());result = prime * result + ((sname == null) ? 0 : sname.hashCode());result = prime * result + ((tel == null) ? 0 : tel.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;StudentInfo other = (StudentInfo) obj;if (addr == null) {if (other.addr != null)return false;} else if (!addr.equals(other.addr))return false;if (cid == null) {if (other.cid != null)return false;} else if (!cid.equals(other.cid))return false;if (sid == null) {if (other.sid != null)return false;} else if (!sid.equals(other.sid))return false;if (sname == null) {if (other.sname != null)return false;} else if (!sname.equals(other.sname))return false;if (tel == null) {if (other.tel != null)return false;} else if (!tel.equals(other.tel))return false;return true;}@Overridepublic String toString() {return "StudentInfo [sid=" + sid + ", sname=" + sname + ", cid=" + cid + ", tel=" + tel + ", addr=" + addr+ "]";}public StudentInfo(Integer sid, String sname, Integer cid, String tel, String addr) {super();this.sid = sid;this.sname = sname;this.cid = cid;this.tel = tel;this.addr = addr;}public StudentInfo() {super();}
}
第三步,我们要准备数据库配置文件
这个自行确定,账号密码请你更改为自己安装数据库的账号密码,我给出我的实例db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mybatis_stu?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useOldAliasMetadataBehavior=true
username=root
password=123456
第四步,创建mybatis配置文件
有了上边三步的基础之后,我们需要配置mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!-- 引入配置文件 请好好的看我 我是db.properties --><properties resource="db.properties"></properties><!-- 配置环境变量 development :开发环境 work :工作环境 --><environments default="development"><environment id="development"><!-- 事务管理 --><transactionManager type="JDBC" /><!-- 配置数据库连接信息 POOLED UNPOOLED --><dataSource type="POOLED"><property name="driver" value="${driver}" /><property name="url" value="${url}" /><property name="username" value="${username}" /><property name="password" value="${password}" /></dataSource></environment></environments><mappers><!-- 加载mapper指向位置 --><mapper resource="mapper/ClassInfoMapper.xml" /><mapper resource="mapper/StudentInfoMapper.xml"></mapper></mappers></configuration>
至此,第四步就完成。
第五步,配置映射
我想说的这上面的每一步都很重要,但是这一步也很重要,我们将相关SQL语句全部写在这里,这一步,我们其实可以说是直接对数据库进行操作,我的理解是这样的,但是不同的人有不同的理解,我也不能去把我的思想强加给别人,对吧?
对了,如果你是初学者,我推荐你了解一下我在本项目的注释
ClassInfoMapper.xml
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace :命名空间 ,就是用来避免命名冲突的,同一个命名空间下面都不能出现相同的id时间上这个就是指向 "ClassInfo.findAll" 测试类的这个属性的ClassInfo代表命名空间,findAll代表id-->
<mapper namespace="ClassInfo"> <!-- 写insert delete update select 语句 每一个语句都有一个id,到时候通过命名空间.id 来获取对应的sql语句执行 通过paramenterType 属性来指定这个sql执行语句的参数 通过resultType属性指定这个sql语句后返回值的类型,是每条结果对应的类型 --><select id="findAll" resultType="com.xh.mybatis.bean.ClassInfo">select cid,cname from classinfo;</select><!-- 假设我们要查询某单一的字段,我们需要的操作是如下 --><select id="find" resultType="com.xh.mybatis.bean.ClassInfo">select cid,cname from classinfowhere cname=#{cname};</select><insert id="add" parameterType="com.xh.mybatis.bean.ClassInfo"><!--#{} 采用预编译的方式 ${} 采用字符串拼接的方法 -->insert into classinfo values(0,#{cname});</insert><!-- 模糊查询 vague '%${parameters}%' %#{parameters}%此时这个语句是有问题的,不能这么写 应该是 '%#{parameters}%' _${parameters}这种模糊查询也是可以的,但是没有%那么灵活,不过你觉得你使用哪个舒服就使用哪个 --><select id="findByVague"resultType="com.xh.mybatis.bean.ClassInfo">select cid,cname from classinfo where cname like'_${parameters}';</select><!--更新表中的数据 --><update id="update"parameterType="com.xh.mybatis.bean.ClassInfo">update classinfo set cname = #{cname} where cid =#{cid};</update><!-- 删除表中的数据 --><delete id="delete"parameterType="com.xh.mybatis.bean.ClassInfo">delete from classinfo where cid = #{cid};</delete>
</mapper>
另一个文件StudentInfoMapper.xml我不会在本篇使用,故而我不在本篇展示,如果你感兴趣的话,请查看下篇。
第六步,测试类的编写
package com.xh.mybatis;import java.io.IOException;
import java.io.InputStream;import java.util.List;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.junit.jupiter.api.Test;import com.xh.mybatis.bean.ClassInfo;public class MyTest {/*** classinfo中的所有的值* @throws IOException*/@Testpublic void test1() throws IOException {try (InputStream reader = Resources.getResourceAsStream("mybatis-config.xml")){//创建sqlSession工厂SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);System.out.println("-----------");//从sqlsession工厂中获取一个sql会话SqlSession sqlSession = sqlSessionFactory.openSession();//通过这个回话执行与sql语句 //将从表中查询的多条数据以作为对象的方式添加到list中List<ClassInfo> cls = sqlSession.selectList("ClassInfo.findAll");//遍历list中的所有的值cls.forEach(System.out::println);sqlSession.close();}}/*** 在classinfo表中添加值 ,非动态添加* @throws IOException*/@Testpublic void test2() throws IOException {try (InputStream reader = Resources.getResourceAsStream("mybatis-config.xml")){//创建sqlSession工厂SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);SqlSession sqlSession = sqlSessionFactory.openSession();//通过这个回话执行与sql语句, /*** 这里的new ClassInfo对象是由于我们创建的表是主键存在主键自增,故而在构造方法中不需要添加cid* 我们可以选择几种方式,这边我们对构造方法可以进行多种构造,让构造方法去选择添加,也可以直接用全部构造* 不够就是我们需要对构造方法进行置空处理*/int result = sqlSession.insert("ClassInfo.add",new ClassInfo("相关"));System.out.println(result);sqlSession.commit();sqlSession.close();}}/*** ClassInfo表中* mybatis查询某数据库中某个值* @throws IOException*/@Testpublic void test3() throws IOException {InputStream reader = Resources.getResourceAsStream("mybatis-config.xml");//创建SqlSession工厂SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);SqlSession sqlSession = sqlSessionFactory.openSession();//我们可以查看到当前查到的对象可以被查出来//ClassInfo obj = sqlSession.selectOne("ClassInfo.find",new ClassInfo("四班"));//ClassInfo.find表示调用Mybatis中的com.xh.bean.ClassInfo下的id=find的sql语句//如果我们使用的是MVC架构进行开发,这个语句应该是属于serviceImpl层调用dao接口的时候ClassInfo obj = sqlSession.selectOne("ClassInfo.find","四班");//查找单个//int result = sqlSession.selectOne("Classinfo.find","四班");System.out.println(obj);sqlSession.commit();sqlSession.close();}/*** 使用模糊查询classInfo中的数据* 没做动态查询* @throws IOException */@Testpublic void test4() throws IOException {InputStream reader = Resources.getResourceAsStream("mybatis-config.xml");//创建sqlSession工厂SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);System.out.println("-----------");//从sqlsession工厂中获取一个sql会话SqlSession sqlSession = sqlSessionFactory.openSession();//通过这个回话执行与sql语句 //将从表中查询的多条数据以作为对象的方式添加到list中List<ClassInfo> cls = sqlSession.selectList("ClassInfo.findByVague","班");//遍历list中的所有的值cls.forEach(System.out::println);sqlSession.commit();sqlSession.close();}/*** 更新表中数据,先从简单的开始,ClassInfo表中的数据* @throws IOException*/@Testpublic void test5() throws IOException {InputStream reader = Resources.getResourceAsStream("mybatis-config.xml");//创建sqlSession工厂SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);System.out.println("-----------");//从sqlsession工厂中获取一个sql会话SqlSession sqlSession = sqlSessionFactory.openSession();//通过这个回话执行与sql语句 //将从表中查询的多条数据以作为对象的方式添加到list中ClassInfo obj = new ClassInfo();obj.setCid(1);obj.setCname("一班");int result = sqlSession.update("ClassInfo.update",obj);if(result > 0) {System.out.println("更新成功");}else {System.out.println("更新失败");}List<ClassInfo> cls = sqlSession.selectList("ClassInfo.findAll");//遍历list中的所有的值cls.forEach(System.out::println);//注意在开启事务的情况下,你不提交数据库是查不到值的sqlSession.commit();sqlSession.close();}/*** 删除* @throws IOException */@Testpublic void test6() throws IOException {InputStream reader = Resources.getResourceAsStream("mybatis-config.xml");//创建sqlSession工厂SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);//从sqlsession工厂中获取一个sql会话SqlSession sqlSession = sqlSessionFactory.openSession();List<ClassInfo> cls = sqlSession.selectList("ClassInfo.findAll");System.out.println("删除之前的数据");cls.forEach(System.out::println);/** ClassInfo obj = new ClassInfo(); obj.setCid(7);*/int result = sqlSession.delete("ClassInfo.delete",8);if(result > 0) {System.out.println("删除成功");}else {System.out.println("删除失败");}//注意在开启事务的情况下,你不提交数据库是查不到值的sqlSession.commit();System.out.println("删除之后的数据");List<ClassInfo> cls1 = sqlSession.selectList("ClassInfo.findAll");//遍历list中的所有的值cls1.forEach(System.out::println);sqlSession.close();}//至此,上边对mybatis的简单操作到此结束
}
至此,我们搭建简单的Mybatis项目就完成了,如果您觉得本文不错的话,请你对本文点一下点赞或者收藏,或者一键三连。您的鼓励将是我最大的动力
mybatis 注意事项:
#{} 和 ${} 的区别
注意:#{}是预编译处理,${}是字符替换
注意:#{}会在mybatis运行的过程中替换为?,调用PreparedStatement的set方法来赋值。
mybatis 在处理$()会将他替换为变量的值。
多使用#{}可以防止sql注入,提高系统安全性。