本文共 16719 字,大约阅读时间需要 55 分钟。
mybatis是一个基于java的持久层框架,特点就是以SQL语句为核心的不完全的ORM(关系型映射)框架
- 持久层:可以将业务数据存储到磁盘,具备长期存储能力,只要磁盘不损坏,在断电或者其他情况下,重新开启系统仍然可以读取到这些数据
- 优点:可以使用巨大的磁盘空间存储相当大的数据,并且很廉价
- 缺点:慢,相对于内存而言
使用mybatis的好处:
- 可以简化传统的JDBC繁琐的连接操作(必须操作Connection,Statement,ResultSet),而使用Mybatis之后,我们只需要提供SQL语句就好了,其余的建立连接,操作Statement,ResultSet,处理JDBC相关异常等等,都可以交给MyBatis处理,我们的关注点集中在SQL语句,和增改删查这些操作层面
- 支持使用简单的XML或者注解来配置和映射原生信息,将接口和java的pojo映射成数据库中的记录
我这里采取的是为IDEA配置MyBatis环境,IDEA默认不支持Mybatis开始,需要自己下载第三方插件来支持,但是MyBatis Plugin是收费的,需要自己破解,具体的破解方式这里就不详述了,大家可以自己在网上查找破解方法
一、准备数据库
首先我们创建一个数据库【mybatis】,在创建一个名为【student】的表
DROP DATABASE IF EXISTS mybatis;CREATE DATABASE mybatis DEFAULT CHARACTER SET utf8;use mybatis;CREATE TABLE student( id int(11) NOT NULL AUTO_INCREMENT, studentID int(11) NOT NULL UNIQUE, name varchar(255) NOT NULL, PRIMARY KEY (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8;INSERT INTO student VALUES(1,1,'我没有三颗心脏');INSERT INTO student VALUES(2,2,'我没有三颗心脏');INSERT INTO student VALUES(3,3,'我没有三颗心脏');
二、创建工程
在IDEA中新建一个java工程,并命名为【HelloMybatis】,然后导入必要的jar包
- mybatis-3.4.6.jar
- mysql-connector-java-5.1.21-bin.jar
三、创建实体类
在package【pojo】下新建实体类【Student】,用于映射student
package pojo;public class Student { int id; int studentID; String name; /* getter and setter */}
四、配置文件mybatis-config.xml
在【src】目录下创建MyBatis的主配置文件mybatis-config.xml,其主要作用是提供连接数据库用的驱动,数据名称,编码方式,账号密码等
五、配置文件Student.xml
在Package【pojo】下新建一个【Student.xml】文件
六、编写测试类
在Package【Test】下创建测试类【TestMyBatis】:
package test;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 pojo.Student;import java.io.IOException;import java.io.InputStream;import java.util.List;public class TestMyBatis { public static void main(String[] args) throws IOException { // 根据 mybatis-config.xml 配置的信息得到 sqlSessionFactory String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 然后根据 sqlSessionFactory 得到 session SqlSession session = sqlSessionFactory.openSession(); // 最后通过 session 的 selectList() 方法调用 sql 语句 listStudent ListlistStudent = session.selectList("listStudent"); for (Student student : listStudent) { System.out.println("ID:" + student.getId() + ",NAME:" + student.getName()); } }}
运行测试:可以获取数据库信息
基本原理:
- 应用程序找MyBatis要数据
- MyBatis从数据库中找来数据
1、通过mybatis-config.xml定位哪个数据库
2、通过Student.xml执行对应的sql语句
3、基于Student.xml把返回的数据库封装在Student对象中
4、把多个Student对象装载一个Student集合中
- 返回一个Student集合
MyBatis——CRUD操作
一、配置Student.xml,首先在SQL映射文件中新增语句,用来支撑CRUD的系列操作
insert into student (id, studentID, name) values (#{id},#{studentID},#{name}) delete from student where id = #{id} update student set name=#{name} where id=#{id}
二、实现增删改查
package test;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 pojo.Student;import java.io.IOException;import java.io.InputStream;import java.util.List;public class TestMyBatis { public static void main(String[] args) throws IOException { // 根据 mybatis-config.xml 配置的信息得到 sqlSessionFactory String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 然后根据 sqlSessionFactory 得到 session SqlSession session = sqlSessionFactory.openSession(); // 增加学生 Student student1 = new Student(); student1.setId(4); student1.setStudentID(4); student1.setName("新增加的学生"); session.insert("addStudent", student1); // 删除学生 Student student2 = new Student(); student2.setId(1); session.delete("deleteStudent", student2); // 获取学生 Student student3 = session.selectOne("getStudent", 2); // 修改学生 student3.setName("修改的学生"); session.update("updateStudent", student3); // 最后通过 session 的 selectList() 方法调用 sql 语句 listStudent ListlistStudent = session.selectList("listStudent"); for (Student student : listStudent) { System.out.println("ID:" + student.getId() + ",NAME:" + student.getName()); } // 提交修改 session.commit();//提交事务 // 关闭 session session.close(); }}
模糊查询:
在Student.xml配置文件中配置SQL映射
写一个测试方法:
@Testpublic void test() throws IOException { // 根据 mybatis-config.xml 配置的信息得到 sqlSessionFactory String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 然后根据 sqlSessionFactory 得到 session SqlSession session = sqlSessionFactory.openSession(); // 模糊查询 Liststudents = session.selectList("findStudentByName", "三颗心脏"); for (Student student : students) { System.out.println("ID:" + student.getId() + ",NAME:" + student.getName()); }}
总结:
- parameterType:要求输入参数的类型
- resultType:输出的类型
- #{}:在MyBatis中代表一种占位符
- ${}:代表一个“拼接符号”,会引入SQL注入,不建议使用
适用场景:对SQL优化要求比较高,或项目需求或业务经常变动
与Hibernate相比:Hibernate学习成本比较高,而SQL语句并不需要开发人员完成,只需要调用API即可,但是缺点是没办法对SQL语句进行修改和优化,而MyBatis虽然需要开发人员自己配置SQL语句,MyBatis来实现映射关系,但是这样的项目可以适应经常变化的项目需求。
使用log4j工具来输出:
将【MyBatis】文件夹下【lib】中的log4j开头的jar包都导入工程并添加依赖,在【src】下新建一个文件夹log4j.properties资源
# Global logging configuration# 在开发环境下日志级别要设置成 DEBUG ,生产环境设为 INFO 或 ERRORlog4j.rootLogger=DEBUG, stdout# Console output...log4j.appender.stdout=org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.layout=org.apache.log4j.PatternLayoutlog4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
1》第一句配置语句,指的是日志输出级别
日志输出级别(7个级别):OFF,FATAL,WARN,INFO,DEBUG,ALL
- 一般常用的日志输出级别分别为 DEBUG、 INFO、 ERROR 以及 WARN,分别表示 “调试级别”、 “标准信息级别”、 “错误级别”、 “异常级别”。如果需要查看程序运行的详细步骤信息,一般选择 “DEBUG” 级别,因为该级别在程序运行期间,会在控制台才打印出底层的运行信息,以及在程序中使用 Log 对象打印出调试信息。
- 如果是日常的运行,选择 “INFO” 级别,该级别会在控制台打印出程序运行的主要步骤信息。“ERROR” 和 “WARN” 级别分别代表 “不影响程序运行的错误事件” 和 “潜在的错误情形”。
- 文件中 “stdout” 这段配置的意思就是将 DEBUG 的日志信息输出到 stdout 参数所指定的输出载体中。
2》第二条配置语句,设置名为stdout的输出端载体是哪种类型
- 目前输出载体有 ConsoleAppender(控制台) FileAppender(文件) DailyRollingFileAppender(每天产生一个日志文件) RollingFileAppender(文件大小到达指定大小时产生一个新的文件) WriterAppender(将日志信息以流格式发送到任意指定的地方)
- 这里要将日志打印到 IDEA 的控制台,所以选择 ConsoleAppender
3》第三条配置语句:意为名为stdout的输出载体的layout(界面布局)是哪种类型
- 目前输出端的界面类型分为 HTMLLayout(以 HTML 表格形式布局) PatternLayout(可以灵活地指定布局模式) SimpleLayout(包含日志信息的级别和信息字符串) TTCCLayout(包含日志产生的时间、线程、类别等信息)
- 这里选择灵活指定其布局类型,即自己去配置布局。
4》第四条配置语句:假如界面布局选择了PatternLayout灵活布局类型,要指定打印的具体格式
- 格式信息配置元素大致如下: %m 输出代码中的指定的信息 %p 输出优先级,即 DEBUG、 INFO、 WARN、 ERROR 和 FATAL %r 输出自应用启动到输出该 log 信息耗费的毫秒数 %c 输出所属的类目,通常就是所在类的全名 %t 输出产生该日志事件的线程名 %n 输出一个回车换行符,Windows 平台为 “
rn
”,UNIX 平台为 “n
” %d 输出日志时的时间或日期,默认个事为 ISO8601,也可以在其后指定格式,比如 %d{yyy MMM dd HH:mm:ss},输出类似:2018 年 4 月18 日 10:32:00 %l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数
1》一对一查询
首先我们来建立一个数据模型:;
use mybatis;CREATE TABLE student ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(255) DEFAULT NULL, card_id int(11) NOT NULL, PRIMARY KEY (id))AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;CREATE TABLE card ( id int(11) NOT NULL AUTO_INCREMENT, number int(11) NOT NULL, PRIMARY KEY (id))AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;INSERT INTO student VALUES (1,'student1',1);INSERT INTO student VALUES (2,'student2',2);INSERT INTO card VALUES (1,1111);INSERT INTO card VALUES (2,2222);
我们查询的SQL语句,可以写成下面这样:
SELECT student.*, card.*FROM student,cardWHERE student.card_id = card.id AND card.number = #{value}
接下来我们分别使用resultType和resultMap来实现查询
(1)使用resultType实现
首先创建学生student表对应的java实体类Student,其中封装的属性信息为响应数据库的字段
package pojo;public class Student { int id; String name; int card_id; /* getter and setter */}
由于最终的查询结果是由resultType指定的,也就是只能映射一个确定的java包装类,但是上面的Student类只包含学生的基本信息,并没有包含Card的信息,所以我们要创建一个最终映射类,以Student类为父类,然后追加Card的信息
package pojo;public class StudentAndCard extends Student { private int number; /* getter and setter /*}
然后在Student.xml映射文件中定义<select>类型的查询语句SQL配置,将之前设计好的SQL语句配置进去,然后指定输出参数属性为resultType,类型为StudentAndCard这个java包装类
然后在测试类中编写测试方法:
@Testpublic void test() throws IOException { // 根据 mybatis-config.xml 配置的信息得到 sqlSessionFactory String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 然后根据 sqlSessionFactory 得到 session SqlSession session = sqlSessionFactory.openSession(); // 找到身份证身份证号码为 1111 的学生 StudentAndCard student = session.selectOne("findStudentByCard",1111); // 获得其姓名并输出 System.out.println(student.getName());}
(2)使用resultMap实现
使用resultMap可以将数据字段映射到名称不一样的响应实体类属性上,重要的是,可以映射实体类中包裹的其他实体类
首先我们来创建一个封装了Card号码和Student实体类的StudentWithCard类:
package pojo;public class StudentWithCard { Student student; int number; int id; /* getter and setter */}
SQL语句依然没有发生变化,但是使用的输出映射属性改为resultMap,其中的映射类型是id为StudentInfoMap的resultMap配置
稍微修改一下测试类,测试使用resultMap实现一对一查询映射:
@Testpublic void test() throws IOException { // 根据 mybatis-config.xml 配置的信息得到 sqlSessionFactory String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 然后根据 sqlSessionFactory 得到 session SqlSession session = sqlSessionFactory.openSession(); // 找到身份证身份证号码为 1111 的学生 StudentWithCard student = session.selectOne("findStudentByCard", 1111); // 获得其姓名并输出 System.out.println(student.getStudent().getName());}
2》一对多查询
首先还是重新建立数据库模型:
use mybatis;CREATE TABLE student ( student_id int(11) NOT NULL AUTO_INCREMENT, name varchar(255) DEFAULT NULL, PRIMARY KEY (student_id))AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;CREATE TABLE class ( class_id int(11) NOT NULL AUTO_INCREMENT, name varchar(255) NOT NULL, student_id int(11) NOT NULL, PRIMARY KEY (class_id))AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;INSERT INTO student VALUES (1,'student1');INSERT INTO student VALUES (2,'student2');INSERT INTO class VALUES (1,'Java课',1);INSERT INTO class VALUES (2,'Java课',2);
然后编写我们的SQL语句:
SELECT student.*FROM student, classWHERE student.student_id = class.student_id AND class.class_id = #{value}
创建对应的实体:
public class Student { private int id; private String name; /* getter and setter */}public class Class { private int id; private String name; private Liststudents; /* getter and setter */}
在 Package【pojo】下新建一个【class.xml】文件完成配置:
编写测试类:
@Testpublic void test() throws IOException { // 根据 mybatis-config.xml 配置的信息得到 sqlSessionFactory String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 然后根据 sqlSessionFactory 得到 session SqlSession session = sqlSessionFactory.openSession(); // 查询上Java课的全部学生 Liststudents = session.selectList("listStudentByClassName", "Java课"); for (Student student : students) { System.out.println("ID:" + student.getId() + ",NAME:" + student.getName()); }}
3》多对多查询
建立数据库模型:
use mybatis;CREATE TABLE students ( student_id int(11) NOT NULL AUTO_INCREMENT, student_name varchar(255) DEFAULT NULL, PRIMARY KEY (student_id))AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;CREATE TABLE courses ( course_id int(11) NOT NULL AUTO_INCREMENT, course_name varchar(255) NOT NULL, PRIMARY KEY (course_id))AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;CREATE TABLE student_select_course( s_id int(11) NOT NULL, c_id int(11) NOT NULL, PRIMARY KEY(s_id,c_id)) DEFAULT CHARSET=utf8;INSERT INTO students VALUES (1,'student1');INSERT INTO students VALUES (2,'student2');INSERT INTO courses VALUES (1,'Java课');INSERT INTO courses VALUES (2,'Java Web课');INSERT INTO student_select_course VALUES(1,1);INSERT INTO student_select_course VALUES(1,2);INSERT INTO student_select_course VALUES(2,1);INSERT INTO student_select_course VALUES(2,2);
设计SQL语句:
SELECT s.student_id,s.student_nameFROM students s,student_select_course ssc,courses cWHERE s.student_id = ssc.s_id AND ssc.c_id = c.course_id AND c.course_name = #{value}
和上述一样创建对应的实体类,这里就不详述了,我们直接配置映射文件【Student.xml】
然后就是测试类,只需要修改调用名称
使用MyBatis开发Web工程时,通过Mapper动态代理机制,可以只编写数据交互接口及方法定义,和对应的Mapper映射文件,具体的交互方法实现由MyBatis来完成,这样可以节省开发DAO层的时间
接下来我们看实例:
1》Mapper代理实例编写
我们编写一个使用Mapper代理查询学生信息的实例,首先还是在【pojo】下新建一个名为StudentMapper.xml的Mapper配置文件,其中包含了对Student的增删改查的SQL配置
INSERT INTO student(student_id, name) VALUES(#{id}, #{name}) DELETE FROM student WHERE student_id = #{id} UPDATE student SET name = #{name} WHERE student_id = #{id}
如果需要使用StudentMapper.xml的Mapper代理,首先需要定义一个接口,名为StudentMapper,然后在里面新建四个方法定义,分别对应StudentMapper.xml中的Student的增删改查的SQL配置,然后将StudentMapper中的namespace改为StudentMapper接口定义的地方,也就是mapper包下的StudentMapper,这样就可以在业务中使用Mapper代理了,接口代码如下:
package mapper;import pojo.Student;public interface StudentMapper { // 根据 id 查询学生信息 public Student findStudentById(int id) throws Exception; // 添加学生信息 public void insertStudent(Student student) throws Exception; // 删除学生信息 public void deleteStudent(int id) throws Exception; // 修改学生信息 public void updateStudent(Student student) throws Exception;}
3》测试动态理:
在测试之前,先将mybatis-config.xml中配置的映射文件修改一下,然后在测试方法中使用SqlSssion类的getMapper方法,并将要加载的Mapper代理的接口类传递进去,就可以获得相关的Mapper代理对象了,使用Mapper代理对象对学生信息进行增删改查:
@Testpublic void test() throws Exception { // 根据 mybatis-config.xml 配置的信息得到 sqlSessionFactory String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 然后根据 sqlSessionFactory 得到 session SqlSession session = sqlSessionFactory.openSession(); // 获取 Mapper 代理 StudentMapper studentMapper = session.getMapper(StudentMapper.class); // 执行 Mapper 代理独享的查询方法 Student student = studentMapper.findStudentById(1); System.out.println("学生的姓名为:" + student.getName()); session.close();}
使用Mapper代理的好处:
- 可以让开发更加简洁,使查询结构更加清晰,工程结构更加规范
在上面的示例中,我们已经有了方便的Mapper代理对象,我们可以进一步省略掉XML的配置信息,进而使用方便的注解来开发MyBatis,让我们来实战一下:
1》为Mapper增加注解
我们把StudeMapper.xml下配置的SQL语句通过注解的方式原封不对动的配置在StudentMapper接口中:
public interface StudentMapper { // 根据 id 查询学生信息 @Select("SELECT * FROM student WHERE student_id = #{id}") public Student findStudentById(int id) throws Exception; // 添加学生信息 @Insert("INSERT INTO student(student_id, name) VALUES(#{id}, #{name})") public void insertStudent(Student student) throws Exception; // 删除学生信息 @Delete("DELETE FROM student WHERE student_id = #{id}") public void deleteStudent(int id) throws Exception; // 修改学生信息 @Update("UPDATE student SET name = #{name} WHERE student_id = #{id}") public void updateStudent(Student student) throws Exception;}
2》修改mybatis-config.xml
将之前配置的映射注释掉,新建一条:
NOTE:映射文件使用resource属性,映射类使用class属性
至于,MyBatis的缓存机制以及延迟加载我们后期学习
转载地址:http://ogeii.baihongyu.com/