一.简介
MyBatis(前身是iBatis)是一个支持普通SQL查询、存储过程以及高级映射的持久层框架,它消除了几乎所有的JDBC代码和参数的手动设置以及对结果集的检索,并使用简单的XML或注解进行配置和原始映射,用以将接口和Java的POJO(Plain Old Java Object,普通Java对象)映射成数据库中的记录,使得Java开发人员可以使用面向对象的编程思想来操作数据库。
MyBatis框架也被称之为ORM(Object/Relation Mapping,即对象关系映射)框架。所谓的ORM就是一种为了解决面向对象与关系型数据库中数据类型不匹配的技术,它通过描述Java对象与数据库表之间的映射关系,自动将Java应用程序中的对象持久化到关系型数据库的表中。ORM框架的工作原理如图1所示。
图1 ORM框架的工作原理
从图1可以看出,使用ORM框架后,应用程序不再直接访问底层数据库,而是以面向对象的方式来操作持久化对象(PO,即Persisent Object),而ORM框架则会通过映射关系将这些面向对象的操作转换成底层的SQL操作。
当前的ORM框架产品有很多,常见的ORM框架有Hibernate和MyBatis。这两个框架的主要区别如下:
● Hibernate:是一个全表映射的框架。通常开发者只需定义好持久化对象到数据库表的映射关系,就可以通过Hibernate提供的方法完成持久层操作。开发者并不需要熟练的掌握SQL语句的编写,Hibernate会根据制定的存储逻辑,自动的生成对应的SQL,并调用JDBC接口来执行,所以其开发效率会高于MyBatis。然而Hibernate自身也存在着一些缺点,例如它在多表关联时,对SQL查询的支持较差;更新数据时,需要发送所有字段;不支持存储过程;不能通过优化SQL来优化性能等。这些问题导致其只适合在场景不太复杂且对性能要求不高的项目中使用。
● MyBatis:是一个半自动映射的框架。这里所谓的“半自动”是相对于Hibernate全表映射而言的,MyBatis需要手动匹配提供POJO、SQL和映射关系,而Hibernate只需提供POJO和映射关系即可。与Hibernate相比,虽然使用MyBatis手动编写SQL要比使用Hibernate的工作量大,但MyBatis可以配置动态SQL并优化SQL,可以通过配置决定SQL的映射规则,它还支持存储过程等。对于一些复杂的和需要优化性能的项目来说,显然使用MyBatis更加合适。
二.项目部署mybatis
1.创建maven项目
java或者web都行
2.引入依赖
在pom.xml中添加依赖
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.26</version> </dependency><!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
3.创建mybatis配置文件
在resources文件夹添加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> <!-- 特别注意:--> <!-- MyBatis中的配置,不但有类型限制,还有顺序限制。--> <!-- 必须按照:<properties>、<settings>、<typeAliases>、<typeHandlers>、…顺序排放。--> <properties resource="jdbc.properties"/> <!-- 1.全局配置参数 --> <settings> <!-- 指定 MyBatis 所用日志的具体实现,未指定时将自动查找 --> <setting name="logImpl" value="STDOUT_LOGGING"/> <!-- 开启自动驼峰命名规则(camel case)映射 --> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> <!-- 2.别名设置 --> <typeAliases> <typeAlias type="" alias=""/> <package name=""/> </typeAliases> <!--3、环境--> <environments default="mysql"> <!-- 开发环境--> <environment id="mysql"> <!-- 事务管理--> <transactionManager type="JDBC"/> <!--数据库连接信息--> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments> <!--4、mapper文件路径--> <mappers> <package name=""/> </mappers> </configuration>
4.使用
4.1创建数据库表
create table tb_students(
sid int primary key auto_increment,
stu_num char(5) not null unique,
stu_name varchar(20) not null,
stu_gender char(2) not null,
stu_age int not null
);
4.2创建实体类
//使用API对实体类操作 //对属性添加get和set方法 @Data //全参构造函数 @AllArgsConstructor //无参构造函数 @NoArgsConstructor //重写tostring方法 @ToString public class Student { private int stuID; private String stuNum; private String stuName; private String stuGender; private int stuAge; }
4.3创建DAO接口,定义操作方法
public interface StudentDAO {
public int insertStudent(Student student);
}
4.5 在resources文件夹创建mappers文件夹,在里面mappers里创建DAO接口的mybatis_mapper.xml映射文件,就相当于接口的实现类,方法的功能是什么就用什么标签,id绑定方法名,parameterType声明参数类型,values是类的属性
<?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文件就相当于DAO接口的实现类-->
<mapper namespace="dao.StudentDAO">
<!-- 需要执行的sql语句,例如select,insert,update,delete,-->
<insert id="insertStudent" parameterType="entity.Student">
insert into tb_student(stu_num,stu_name,stu_gender,stu_age)
values (#{stuNum},#{stuName},#{stuGender},#{stuAge})
</insert>
</mapper>
4.6 将映射文件添加到mybatis_config.xml文件
<mappers> <mapper resource="mappers/mybatis_mapper.xml"/> </mappers>
5.单元测试
导入测试包
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency>
在DAO接口右键选择generate,
选择test,
将所有方法添加上
自动在 生成test文件夹测试方法
@org.junit.Test
public void insertStudent() {
try {
//加载mybatis配置文件
InputStream is = Resources.getResourceAsStream("mybatis_config.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//会话工厂
SqlSessionFactory factory = builder.build(is);
//与数据库的连接即mybatis的操作对象,会话
SqlSession sqlSession = factory.openSession();
StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);
int i=studentDAO.insertStudent(new Student(0,"Y8021","小明","男",18));
// 手动提交事务
sqlSession.commit();
if (i==1){
System.out.println("添加成功");
}else {
System.out.println("添加失败");
}
} catch (IOException e) {
e.printStackTrace();
}
}
查询时
<!-- <select id="listStudent" resultType="entity.Student">-->
<!-- 如果数据库的字段名和类的属性名一样可以直接存储到Student类-->
<!-- select * from tb_students-->
<!-- 1如果数据库的字段名和类的属性名不一样,则将字段名匿名和属性名一样再存储到Student类-->
<!-- select-->
<!-- sid stuID,-->
<!-- stu_num stuNum,-->
<!-- stu_name stuName,-->
<!-- stu_gender stuGender,-->
<!-- stu_age stuAge-->
<!-- from tb_students-->
<!-- </select>-->
<!-- 2如果数据库的字段名和类的属性名不一样,则将字段名和属性名映射,再存储到Student类-->
<!-- 字段名与属性映射-->
<resultMap id="columnToProperty" type="entity.Student">
<id column="sid" property="stuID"/>
<result column="stu_num" property="stuNum"/>
<result column="stu_name" property="stuName"/>
<result column="stu_gender" property="stuGender"/>
<result column="stu_age" property="stuAge"/>
</resultMap>
<select id="listStudent" resultMap="columnToProperty">
select sid ,
stu_num ,
stu_name ,
stu_gender ,
stu_age
from tb_students
</select>
1.如果方法只有一个简单类型或者字符串类型的参数,在Mapper配置中可以直接通过#{key}获取
2.如果方法有一个对象类型的参数,在Mapper配置中可以直接通过#{属性名}获取指定属性值
在DAO中
public int deleteStudent(String stuNum);
在mapper 里
<delete id="deleteStudent" parameterType="String"> delete from tb_students where stu_num = #{stuNum} </delete>
测试:
public void deleteStudent() {
try {
//加载mybatis配置文件
InputStream is = Resources.getResourceAsStream("mybatis_config.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//会话工厂
SqlSessionFactory factory = builder.build(is);
//与数据库的连接即mybatis的操作对象,会话
SqlSession sqlSession = factory.openSession();
StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);
int i= studentDAO.deleteStudent("Y8021");
sqlSession.commit();
if (i==1){
System.out.println("删除成功");
}else {
System.out.println("删除失败");
}
} catch (IOException e) {
e.printStackTrace();
}
3.如果方法有多个参数,可以将其转换成Map类型,在Mapper配置中可以直接通过HashMap的key值#{key}获取指定属性值
在DAO中:
public List<Student> listStudentPage(HashMap<String,Integer> map);
在mapper中:
<select id="listStudentPage" resultMap="columnToProperty"> select sid , stu_num , stu_name , stu_gender , stu_age from tb_students limit #{start},#{pageSize} </select>
测试:
public void listStudentPage() {
try {
InputStream is=Resources.getResourceAsStream("mybatis_config.xml");
SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
SqlSessionFactory factory= builder.build(is);
SqlSession sqlSession= factory.openSession();
StudentDAO studentDAO=sqlSession.getMapper(StudentDAO.class);
//用hashmap传参
HashMap<String,Integer> hashMapmap=new HashMap<>();
hashMapmap.put("start",0);
hashMapmap.put("pageSize", 2);
List<Student> list = studentDAO.listStudentPage(hashMapmap);
sqlSession.commit();
assertNotNull(list);
list.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
4.如果方法有多个参数,在Mapper配置中使用arg0,arg1或者(param1,param2)...获取参数
在DAO中:
public List<Student> listStudentPage(int start, int pageSize);
在mapper里:
<select id="listStudentPage" resultMap="columnToProperty"> select sid , stu_num , stu_name , stu_gender , stu_age from tb_students //limit #{arg0},#{arg1} limit #{param1},#{param2}
方便起见在DAO可以用@Param("start")给参数起别名,
public List<Student> listStudentPage(@Param("start") int start,@Param("pageSize") int pageSize);
在mapper使用别名获取
limit #{satrt},#{pageSize}
测试:
public void listStudentPage() {
try {
InputStream is=Resources.getResourceAsStream("mybatis_config.xml");
SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
SqlSessionFactory factory= builder.build(is);
SqlSession sqlSession= factory.openSession();
StudentDAO studentDAO=sqlSession.getMapper(StudentDAO.class);
List<Student> list = studentDAO.listStudentPage(0,2);
sqlSession.commit();
assertNotNull(list);
list.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}