目录
啥是框架?
按我的理解:框架的出现是为了让代码的编写更加的方便简洁,代码越到后面越少,框架负责把重复性的复杂的代码都省略掉,在编写代码时主要负责编写有变通性的代码。
Mybatis框架详解
要有一定的增删改查,操作数据库基础
Mybatis框架:
MyBatis专注于SQL本身,是一个足够灵活的DAO层解决方案,适用于性能要求较高或者需求多变的互联网项目,红色字体的是复制的;到后面和Spring框架联动后编写代码会更加方便。
mybatis配置思路
1.先整合mybatis的环境
2.创建包结构以及导入外部包
3.编辑mybatis配置文件
4.编写代码
5.测试
随便设计个数据库
Mysql数据库表,要有外键关系。下面设计一个表可以参考
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for grade
-- ----------------------------
DROP TABLE IF EXISTS `grade`;
CREATE TABLE `grade` (
`GradeID` int(0) NOT NULL AUTO_INCREMENT,
`GradeName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
PRIMARY KEY (`GradeID`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`id` int(0) NOT NULL AUTO_INCREMENT COMMENT '这是一个序号',
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '可以存储有限长度1~一万多',
`bigname` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '家庭住址',
`riqi` datetime(0) NULL DEFAULT NULL COMMENT '这是时间类型',
`GradeID` int(0) NOT NULL COMMENT '这是外键',
`age` int(0) NULL DEFAULT NULL COMMENT '年龄',
PRIMARY KEY (`id`) USING BTREE,
INDEX `fk_student_grade`(`GradeID`) USING BTREE,
CONSTRAINT `fk_student_grade` FOREIGN KEY (`GradeID`) REFERENCES `grade` (`GradeID`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 21 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
创建idea中的maven项目
都别选直接下一步,你真想选我也没办法。
导入需要的依赖
<?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>com.xinxi2</groupId><!--这个每个人都不太一样别复制-->
<artifactId>Student_Mybatis</artifactId><!--这个也是-->
<version>1.0-SNAPSHOT</version><!--这个你猜是不是-->
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!--mysql 数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
创建目录、bean层、dao层和一个测试类
先创建简单的层结构,主要让你学会Mybatis,能测试就行
配置Mybatis数据库连接
在resources里面创建mybatis.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>
<properties resource="jdbc.properties"></properties><!--获取jdbc文件-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/><!--这四个都要和jdbc配置文件映射上-->
<property name="url" value="${url}"/>
<property name="username" value="${user}"/>
<property name="password" value="${pwd}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/xinxi2/dao/StudentMapper.xml"/><!--要使用Mapper.xml都要有这一步-->
<mapper resource="com/xinxi2/dao/GradeMapper.xml"/><!--有几个就写几个-->
</mappers>
</configuration>
创建bean层
Student类
package com.xinxi2.bean;
import java.util.Date;
public class Student {
private int id;
private String name;
private String bigname;
private Date riqi;
private int gradeid;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBigname() {
return bigname;
}
public void setBigname(String bigname) {
this.bigname = bigname;
}
public Date getRiqi() {
return riqi;
}
public void setRiqi(Date riqi) {
this.riqi = riqi;
}
public int getGradeid() {
return gradeid;
}
public void setGradeid(int gradeid) {
this.gradeid = gradeid;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Grade类
package com.xinxi2.bean;
public class Grade {
private int GradeID;
private String GradeName;
public int getGradeID() {
return GradeID;
}
public void setGradeID(int gradeID) {
GradeID = gradeID;
}
public String getGradeName() {
return GradeName;
}
public void setGradeName(String gradeName) {
GradeName = gradeName;
}
}
创建dao层——重中之重
基础sql
先创建一个Mapper接口,再简单的写个增、删、改、查接口
package com.xinxi2.dao;
import com.xinxi2.bean.Student;
import java.util.List;
public interface StudentMapper {
List<Student> getList();
int addStudent(Student student);
int updateStudent(Student student);
int deleteStudentbyId(int id);
}
再创建一个Mapper的XML配置文件来实现这个接口
映射规则
mapper标签中的namespace属性映射的是你刚刚创建的Mapper接口,映射的是你刚刚创建的Mapper接口的地址,映射完毕后Mapper接口和MapperXML配置文件的图标会变为一直蓝鸟和一直红鸟如果没有去网上搜索一下,下载一个idea中的Mybatis插件就好了,巨简单,我就不教了。
SpringXMl实现接口
<?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.xinxi2.dao.StudentMapper">
<select id="getList" resultType="com.xinxi2.bean.Student">
SELECT id,name,bigname,riqi,GradeID,age FROM student
</select>
<insert id="addStudent" parameterType="com.xinxi2.bean.Student" keyProperty="id" keyColumn="id" useGeneratedKeys="true">
insert into student(id,name,bigname,riqi,GradeID,age)
values (#{id},#{name},#{bigname},#{riqi},#{gradeid},#{age})
</insert>
<update id="updateStudent" parameterType="com.xinxi2.bean.Student">
update student
set name=#{name},bigname={bigname},riqi=#{riqi},GradeID=#{gradeid},age=#{age}
where id=#{id}
</update>
<delete id="deleteStudentbyId" parameterType="int">
delete from student where id=#{id}
</delete>
</mapper>
你们应该也发现了每个标签都有大差不差的属性,下面是我认为常用的一些属性
id | (都能用)与namespace接口中对应的方法作的映射 |
parameterType | (都能用)传入的参数格式 |
resultType | (用于查询)返回的数据类型,当返回多个参数的时候,建议使用 resultMap |
resultMap | (用于查询)返回的数据类型,相当于对 resultType的封装。resultType、resultMap两者只能存在一个如果使用resultMap的话要把查询出来的几列数据都要声明一下。 |
keyProperty | (仅对 insert 和 update 有用)唯一标记一个属性,MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值,默认:unset。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 |
useGeneratedKeys | (仅对 insert 和 update 有用)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系数据库管理系统的自动递增字段),默认值:false。 |
keyColumn | (仅对 insert 和 update 有用)通过生成的键值设置表中的列名,这个设置仅在某些数据库(像 PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 |
基础sql测试
测试的漏洞
在测试之前我们要先把dao层的MapperXML配置文件放在target里面的dao层中
测试时是运行target里面的代码,我们这样写现在是有一点问题因为还没有学spring框架,这样写方便学习(注意)每次编写完一次MapperXML的文件都要复制进来一次
开始测试
package com.xinxi2;
import com.xinxi2.bean.Student;
import com.xinxi2.dao.StudentMapper;
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 java.io.InputStream;
import java.util.Date;
import java.util.List;
public class Test {
public static void main(String[] args) {
//声明mybatis配置文件
String resources="mybatis.xml";
InputStream inputStream=null;
SqlSessionFactory sqlSessionFactory=null;
//获得sqlSession对象
SqlSession sqlSession=null;
try {
inputStream= Resources.getResourceAsStream(resources);
sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
sqlSession=sqlSessionFactory.openSession();
//创建StudentDao层对象
StudentMapper studentMapper=sqlSession.getMapper(StudentMapper.class);
List<Student> list=studentMapper.getList();
for (Student student:list){
System.out.println(student.getName());//输出name
}
Student student=new Student();
student.setName("牛牛");
student.setBigname("牛圈");
student.setRiqi(new Date());
student.setGradeid(1);
student.setAge(18);
studentMapper.addStudent(student);
//新镇修改删除都要有提交事务
sqlSession.commit();
//新增后获取的自增id
System.out.println(student.getId());
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭sqlSession
sqlSession.close();
}
}
}
修改和删除就先省略了,我相信你会
进阶带参sql查询
单参数方式
一个参数的情况下但是两个参数呐?这时候就需要用到我们的@Param()注解了
@Param()注解方式
如果有两个及以上参数并且使用了@Param()注解就不需要parameterType属性了
Map方式
如果使用map方式的话在测试时,要把map当作数组来使用,sql中的#{name}要在创建map键值里要有一个k值是name
实体类方式
上面的三种方式是在特殊的情况下使用,真正常用的是实体类的方式
实体类方式测试
package com.xinxi2;
import com.xinxi2.bean.Student;
import com.xinxi2.dao.StudentMapper;
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 java.io.InputStream;
import java.util.Date;
import java.util.List;
public class Test {
public static void main(String[] args) {
//声明mybatis配置文件
String resources="mybatis.xml";
InputStream inputStream=null;
SqlSessionFactory sqlSessionFactory=null;
//获得sqlSession对象
SqlSession sqlSession=null;
try {
inputStream= Resources.getResourceAsStream(resources);
sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
sqlSession=sqlSessionFactory.openSession();
//创建StudentDao层对象
Student student=new Student();
student.setName("牛牛");
student.setBigname("牛圈");
student.setId(1);
StudentMapper studentMapper=sqlSession.getMapper(StudentMapper.class);
List<Student> list=studentMapper.getListbyStudent(student);
for (Student student1:list){
System.out.println(student1.getName());//输出name
}
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭sqlSession
sqlSession.close();
}
}
}
连表查询
连表查询分为一对多、多对一和多对多,连表查询的话就只能使用resultMap属性来查询。
子表多对一
要先在子表的bean层添加主表对象并且进行封装
private Grade grade=new Grade();
public Grade getGrade() {
return grade;
}
public void setGrade(Grade grade) {
this.grade = grade;
}
多对一MapperXML层
resultMap标签的 id属性下面用自己命名,type属性映射子表实体类的地址
resultMap标签的 id标签要和数据库id对应,property是和实体类对应column和数据库对应,result标签也一样
association标签 property属性对应刚才实体类添加的主表实体类的名称,javaType属性映射父表实体类的地址
<?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.xinxi2.dao.StudentMapper">
<resultMap id="StudentMap" type="com.xinxi2.bean.Student">
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<result property="bigname" column="bigname"></result>
<result property="riqi" column="riqi"></result>
<result property="age" column="age"></result>
<association property="grade" javaType="com.xinxi2.bean.Grade">
<id property="gradeID" column="GradeID"></id>
<result property="gradeName" column="GradeName"></result>
</association>
</resultMap>
<select id="getList" resultMap="StudentMap">
SELECT s.id,name,bigname,age,g.GradeName FROM `student` s,grade g
where s.GradeID=g.GradeID
</select>
</mapper>
多对一测试类
StudentMapper studentMapper=sqlSession.getMapper(StudentMapper.class);
List<Student> list=studentMapper.getList();
for (Student student1:list){
//getGrade()是父类对象的get方法后面的getGradeName()方法是父类的班级名称的get方法
System.out.println(student1.getName()+student1.getGrade().getGradeName());
}
父表一对多
要先在父表的bean层添加子表列表方法并且进行封装,因为一个班级有多个学生
private List<Student> studentList=new ArrayList<>();
public List<Student> getStudentList() {
return studentList;
}
public void setStudentList(List<Student> studentList) {
StudentList = studentList;
}
一对多MapperXML层
一对多和多对一的sql语句都不用动,resultMap标签type属性和下面的互换一下
collection标签 property属性对应刚才实体类添加的子表实体类列表的名称,ofType属性映射子表实体类的地址
<?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.xinxi2.dao.GradeMapper">
<resultMap id="GradeMap" type="com.xinxi2.bean.Grade">
<id property="gradeID" column="GradeID"></id>
<result property="gradeName" column="GradeName"></result>
<collection property="studentList" ofType="com.xinxi2.bean.Student">
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<result property="bigname" column="bigname"></result>
<result property="riqi" column="riqi"></result>
<result property="age" column="age"></result>
</collection>
</resultMap>
<select id="getGradeList" resultMap="GradeMap">
SELECT s.id,name,bigname,age,g.GradeName FROM `student` s,grade g
where s.GradeID=g.GradeID
</select>
</mapper>
多对一测试类
GradeMapper gradeMapper=sqlSession.getMapper(GradeMapper.class);
List<Grade> list=gradeMapper.getGradeList();
for (Grade grade:list){
System.out.println(grade.getGradeName());//输出班级name
for (Student student1:grade.getStudentList()){
System.out.println(student1.getName()+student1.getBigname());
}
}
动态Sql
动态Sql更方便业务实现,mybatis提供了许多标签来使用,使代码更加的简便
where标签
<select id="getListbyStudent" resultType="com.xinxi2.bean.Student" parameterType="com.xinxi2.bean.Student">
select * form student
<where>
<if test="name!=null">
and name=#{name}
</if>
<if test="bigname!=null">
and bigname=#{bigname}
</if>
</where>
</select>
and一定要加在条件前面,mybatis会自动添加where 和 and,带#{}的name是实体类里面的,不带的是数据库的
set标签
<update id="updateStudent" parameterType="com.xinxi2.bean.Student">
update student
<set>
<if test="name!=null">
name=#{name},
</if>
<if test="bigname!=null">
bigname=#{bigname},
</if>
</set>
where id=#{id}
</update>
set标签多数用于修改,而set标签是在条件后面加英语符号的”,“。
foreach标签
接口:
List<Student> getListbyList(List<String> list);//参数是列表
实现类:
<select id="getListbyNames" resultType="com.xinxi2.bean.TSysUser">
SELECT * FROM `t_sys_user` where realName in
<foreach collection="list" open="(" separator="," close=")" item="goods">
#{goods}
</foreach>
</select>
foreach标签 collection属性对应接口的参数列表,open列表遍历完的开头,separator是列表中格格元素之间的分隔符,open列表遍历完的结尾,item集合中元素迭代时的别名。
trim标签
trim标签说白了就是可以自定义动态sql,前面的where标签和set标签都可以使用trim来自定义。
自定义where
<select id="getListbyStudent01" resultType="com.xinxi2.bean.Student" parameterType="com.xinxi2.bean.Student">
select * form student
<trim prefix="where" prefixOverrides="or|and">
<if test="name!=null">
and name=#{name}
</if>
<if test="bigname!=null">
and bigname=#{bigname}
</if>
</trim>
</select>
自定义update
<update id="updateListbyStudent02" parameterType="com.xinxi2.bean.Student">
update student
<trim prefix="set" suffixOverrides="," suffix="where id=#{id}">
<if test="name!=null">
and name=#{name},
</if>
<if test="bigname!=null">
and bigname=#{bigname},
</if>
</trim>
</update>
prefix | 给sql语句拼接的前缀 |
suffix | 给sql语句拼接的后缀 |
prefixOverrides | 去除sql语句前面的关键字或者字符,该关键字或者字符由prefixOverrides属性指定,假设该属性指定为"AND",当sql语句的开头为"AND",trim标签将会去除该"AND" |
suffixOverrides | 去除sql语句后面的关键字或者字符,该关键字或者字符由suffixOverrides属性指定 |