MyBatis笔记
Posted 啊qie!
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis笔记相关的知识,希望对你有一定的参考价值。
一、框架概述
1.1、三层架构
三层架构包含的三层:
界面层:和用户打交道的,接收用户的请求参数,显示处理结果的。对应的包是controller包。
业务逻辑层:接收了界面层传递的数据,计算逻辑,调用数据库,获取数据。对应的包是service包。
数据访问层:就是访问数据库,执行对数据的查询,修改,删除等等。对应的包是dao包。
三层的处理请求的交互:
用户使用界面层–> 业务逻辑层—>数据访问层(持久层)–>数据库(mysql)
如图:
为什么使用三层:
1、结构清晰、耦合度低,各层分工明确;
2、可维护性高、可扩展行高;
3、有利于各层逻辑的复用。
1.2、什么是框架
框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;框架是可被应用开发者定制的应用骨架、模板。
简单的说,框架其实是半成品软件,就是一组组件,供你使用完成你自己的系统。框架是安全的,可复用的,不断升级的软件。
1.3、MyBatis框架
一个框架,早期叫做ibatis,代码在GitHub。
MyBatis是MyBatis SQL Mapper Framework for Java(sql映射框架)
(1)sql mapper:sql映射
可以把数据库表中的一行数据,映射为一个java对象。一行数据可以看作是一个java对象。操作这个对象就相当于操作表中的数据.
(2)Data Access Object(DAOs):数据访问,对数据库执行增删改查。
1.3.1、使用JDBC的缺陷
1、代码比较多,开发效率低
2、需要关注Connection,Statement、ResultSet对象创建和销毁
3、对ResultSet查询的结果,需要自己封装为List
4、重复的代码比较多
1.3.2、MyBatis解决的主要问题
减轻使用JDBC的复杂性,不用编写重复的创建Connection,Statement;不用编写关闭资源代码。直接使用java对象,表示结果数据。
1.3.3、MyBatis提供的功能
1、 提供了创建Connection ,Statement, ResultSet的能力 ,不用开发人员创建这些对象了;
2. 提供了执行sql语句的能力, 不用你执行sql;
3. 提供了循环sql, 把sql的结果转为java对象, List集合的能力;
4. 提供了关闭资源的能力,不用你关闭Connection, Statement, ResultSet。
开发人员做的是:提供sql语句。
MyBatis是一个sql映射框架,提供的数据库的操作能力,增强的JDBC,使用MyBatis让开发人员集中精神写sql就可以了,不必关心Connection ,Statement, ResultSet的创建,销毁,sql的执行。
二、MyBatis使用传统Dao开发方式
2.1、编写Student实体类
public class Student
//定义属性,目前要求是属性名和列名一致
private int id;
private String name;
private String email;
private int age;
//构造方法、set、get、toString
2.2、编写StudentDao接口
public interface StudentDao
//查询student表中所有数据
List<Student> selectStudents();
//向student表中插入数据,参数student表示向数据库表中插入的数据
//返回值int表示执行insert操作后影响数据库的行数
int insertStudents(Student student);
2.3、编写Dao接口Mapper映射文件StudentDao.xml
<?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.dao.StudentDao">
<!--
select:表示查询操作
id:你要执行的sql语法的唯一标识,mybatis会使用这个id的值来找到要执行的sql语句
可以自定义,但是前要求使用接口中的方法名称
resultType:表示结果类型的,是sql语句执行后得到ResultSet,遍历这个ResultSet得到java对象的类型
值写的是类型的全限定名称
-->
<select id="selectStudents" resultType="com.domain.Student">
select id,name,email,age from student order by id
</select>
<insert id="insertStudents">
insert into student values(#id,#name,#email,#age)
</insert>
</mapper>
2.4、创建MyBatis主配置文件
<?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>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--环境配置:数据库的连接信息
default:必须和某个environment的id值一样
告诉mybatis使用哪个数据库的连接信息。也就是访问哪个数据库
-->
<environments default="mydev">
<!--environment : 一个数据库信息的配置,环境
id:一个唯一值,自定义,表示环境的名称
-->
<environment id="mydev">
<!--transactionManager:mybatis的事务类型
type:JDBC(表示使用jdbc中的Connection对象的commit,rollback做事务处理)-->
<transactionManager type="JDBC"/>
<!-- dataSource:表示数据源,连接数据库的
type:表示数据源的类型,POOLED表示使用连接池-->
<dataSource type="POOLED">
<!--driver,url,username,password是固定的,不能自定义-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ssm"/>
<property name="username" value="root"/>
<property name="password" value="6269131.x"/>
</dataSource>
</environment>
</environments>
<!--sql映射文件的位置-->
<mappers>
<!--一个mapper标签它指定一个文件的位置。
从类路径开始的路径信息。 target/clasess(类路径)-->
<mapper resource="com/dao/StudentDao.xml"/>
</mappers>
</configuration>
配置日志功能:在mybatis.xml文件加入日志配置,可以在控制台输出执行是sql语句和参数
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
2.5、创建工具类(MyBatisUtils类)
public class MybatisUtil
private static SqlSessionFactory factory = null;
static
//1、定义mybatis主配置文件的名称,从类路径的根开始
String config = "mybatis.xml";
try
InputStream in = Resources.getResourceAsStream(config);
//创建SqlSessionFactory对象,使用SqlSessionFactoryBuilder
factory = new SqlSessionFactoryBuilder().build(in);
catch (IOException e)
e.printStackTrace();
//获取SqlSession对象
public static SqlSession getSqlSession()
SqlSession sqlSession = null;
if(factory != null)
sqlSession = factory.openSession();
return sqlSession;
2.6、创建Dao接口的实现类
public class StudentDaoImpl implements StudentDao
public List<Student> selectStudents()
//获取SqlSession对象
SqlSession sqlSession = MybatisUtil.getSqlSession();
String sqlId = "com.dao.StudentDao.selectStudents";
List<Student> studentList = sqlSession.selectList(sqlId);
sqlSession.close();
return studentList;
public int insertStudents(Student student)
SqlSession sqlSession = MybatisUtil.getSqlSession();
String sqlId = "com.dao.StudentDao.insertStudents";
int nums = sqlSession.insert(sqlId,student);
sqlSession.commit();
sqlSession.close();
return nums;
2.7、创建测试类
public class TestMybatis
@Test
public void selectTest()
StudentDao dao = new StudentDaoImpl();
List<Student> students = dao.selectStudents();
for(Student stu : students)
System.out.println(stu);
@Test
public void insertTest()
StudentDao dao = new StudentDaoImpl();
Student student = new Student(1017,"张三","zhangsan@qq.com",40);
int nums = dao.insertStudents(student);
System.out.println(nums);
2.8、主要类介绍
(1)、Resources:mybatis中的一个类,负责读取主配置文件,返回不同类型的IO流对象。
InputStream in = Resources.getResourceAsStream(“mybatis.xml”);
(2)、SqlSessionFactoryBuilder : 创建SqlSessionFactory对象。
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder()
SqlSessionFactory factory = builder.build(in);
SqlSessionFactoryBuilder对象在创建完工厂对象后,即可被销毁。
(3)、SqlSessionFactory接口
重量级对象, 程序创建一个对象耗时比较长,使用资源比较多。
在整个项目中,有一个就够用了。
SqlSessionFactory:接口,接口实现类: DefaultSqlSessionFactory
SqlSessionFactory作用: 获取SqlSession对象。SqlSession sqlSession = factory.openSession();
openSession()方法说明:
1. openSession() :无参数的, 获取是非自动提交事务的SqlSession对象
2. openSession(boolean): openSession(true) 获取自动提交事务的SqlSession.
openSession(false) 非自动提交事务的SqlSession对象
(4)、SqlSession接口:定义了操作数据的方法 例如 selectList() ,insert(),update(), delete(), commit(), rollback()。
SqlSession接口的实现类DefaultSqlSession。
SqlSession对象不是线程安全的,需要在方法内部使用,在执行sql语句前,使用openSession()获取SqlSession对象。在执行完sql语句后,需要关闭它,执行SqlSession.close(),这样才能保证它的使用是线程安全的。
三、MyBatis实现Dao的动态代理
3.1Dao的动态代理
使用SqlSession.getMapper(dao接口.class)获取dao接口的对象。
这样就不需要Dao接口的实现类
public class MybatisTest
@Test
/**
* 使用Mybatis的动态代理机制,使用sqlSession.getMapper(dao接口)
* getMapper能获取dao接口对应的实现类对象
*/
public void selectTest()
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
//com.sun.proxy.$Proxy9: jdk的动态代理
System.out.println(dao.getClass().getName());
//调用dao的方法执行数据库的操作
List<Student> students = dao.selectStudents();
for(Student stu : students)
System.out.println(stu);
@Test
public void insertTest()
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
Student student = new Student(1032,"李四","lisi@sina.com",21);
int nums = dao.insertStudents(student);
sqlSession.commit();
System.out.println(nums);
3.2、深入理解参数
MyBatis传递参数:从java代码中把数据传入到mapper文件的sql语句中。
3.2.1、parameterType
parameterType:写在mapper文件中的一个属性。表示dao接口中方法的参数的数据类型。
parameterType它的值是java数据类型的全限定名称或者是mybatis定义的别名
eg:parameterType = “int”
parameterType = “java.lang.Integer”
注意:parameterType不是强制的,mybatis通过反射机制能够发现接口参数的数据类型。所以可以没有,一般我们也不写。
eg:
例如StudentDao接口
public Student selectStudentById(Integer id)
<select id="selectStudentById" parameterType="java.lang.Integer" resultType="com.domain.Student">
select id,name,email,age from student where id = #studentId
</select>
3.2.2、一个简单类型的参数
简单类型:mybatis把java的基本数据类型和String都叫简单数据类型。
在mapper文件获取简单类型的一个参数的值,使用#任意字符
例如StudentDao接口
public Student selectStudentById(int id)
mapper:
<select id="selectStudentById" resultType="com.domain.Student">
select id,name,email,age from student where id = #studentId
</select>
3.2.3、多个参数,使用@Param命名参数
当Dao接口方法有多个参数,需要通过名称使用参数。在方法形参前面加入@Param(“自定义参数名”),mapper文件使用#自定义参数名。
接口方法:
List selectMultiParam(@Param(“myName”) String name,@Param(“myAge”) int age);
mapper:
<select id="selectMultiParam" resultType="com.domain.Student">
select id,name,email,age from student where name = #myName or age = #myAge
</select>
3.2.4、多个参数-使用java对象
使用java对象传递参数,java的属性值就是sql需要的参数值。每一个属性就是一个参数。
语法格式:#属性名,javaType=java中数据类型名称,jdbcType=数据库数据类型名称 这是最为完整的方式。但是javaType、jdbcType的值mybatis通过反射机制可以获取,一般不需要设置。常用格式:#属性名
接口方法:
List selectMultiStudent(Student student);
mapper:
<select id="selectMultiStudent" resultType="com.domain.Student">
select id,name,email,age from student where
name = #name or age = #age
</select>
或者为:
<select id="selectMultiStudent" resultType="com.domain.Student">
select id,name,email,age from student where name = #name,javaType=java.lang.String,jdbcType=VARCHAR
or age = #age,javaType=java.lang.Integer,jdbcType=INTEGER
</select>
3.2.5、多个参数-按位置
参数位置从0开始,引用参数语法==#arg位置==,第一个参数是#arg0,第二个参数是#arg1
注意:mybatis-3.3版本和之前的版使用#0,#1方式,从mybatis-3.4开始使用#arg0方式。
接口方法:
List selectMultiPosition(String name,int age);
mapper:
<!--多个参数使用位置-->
<select id="selectMultiPosition" resultType="com.domain.Student">
select id,name,email,age from student where
name = #arg0 or age = #arg1
</select>
3.2.6、多个参数-使用Map
Map集合可以存储多个值,使用Map向mapper文件一次传入多个参数,Map集合使用String的key,Object类型的值存储参数。mapper文件使用==#key==引用参数值。
比如:
HashMap<String, Object> map = new HashMap<>();
map.put("name","zhangsan");
map.put("age",20);
接口方法:
List selectMultiMap(Map<String,Object> map);
mapper文件:
<!--多个参数使用Map,使用语法:#map的key-->
<select id="selectMultiMap" resultType="com.domain.Student">
select id,name,email,age from student where
name = #name or age = #age
</select>
3.2.7、# 和 $
#:占位符,告诉mybatis使用实际的参数值代替。并使用PrepareStatement对象执行sql语句,#…代替sql语句的 “ ?”。这样做更安全、通常也是首选做法。
例如:
select id,name, email,age from student where id=#studentId
#的结果:select id,name, email,age from student where id=?
$:字符串替换,告诉mybatis使用 $ 包含的“字符串”替换所在位置。使用Statement把sql语句和$的内容连接起来,主要用在替换表名、列名,不同列排序等操作。
例如:
select id,name, email,age from student where id=$studentId
$的结果:select id,name, email,age from student where id=1001
相当于:String sql=“select id,name, email,age from student where id=” + “1001”;
#和$的区别:
1、#使用?在sql语句中做占位的,使用PrepareStatement执行sql,效率高
2、#能够避免sql注入,更安全
3、$不使用占位符,是字符串连接的方法,使用Statement对象执行sql,效率低
4、$有sql注入的风险,缺乏安全性
5、$可以替换表名或者列名
3.3、MyBatis的输出结果
3.3.1、resultType
resultType:执行sql得到ResultSet转换的类型,使用类型的完全限定名或者别名。注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。
1、简单类型
接口方法:int countStudent();
mapper文件:
<select id="countStudent" resultType="java.lang.Integer">
select count(*) from student
</select>
2、对象类型
接口方法:List<Student> selectStudent( int id);
mapper文件:
<select id="selectStudent" resultType="com.domain.Student">
select id,name from student where id = #id
</select>
框架的处理:使用构造方法创建对象,调用setXXX给属性赋值。
Student student = new Student();
注意:Dao接口方法的返回值是集合类型,需要指定集合中的类型,不是集合本身。
3、Map
sql的查询结果作为Map的key和value。推荐使用Map<Object,Object>.
注意:Map作为接口返回值,sql语句的查询结果最多只能有一条记录,大于一条记录是错误。
接口方法:Map<Object,Object> selectMapById(int id);
mapper文件:
<!--返回Map (用的少)
1、列名是Map的key,列值是Map的value
2、最多只能返回一行记录,多一行是错误的
-->
<select id="selectMapById" resultType="java.util.HashMap">
select id,name,email,age from student where id = #id
</select>
测试方法:
@Test
public void testSelectMapById()
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
Map<Object, Object> map = dao.selectMapById(1017);
System.out.println(map);
3.3.2、resultMap
resultMap可以自定义sql的结果和java对象属性的映射关系。更灵活的把列值赋值给指定属性。
常用在列名和java对象属性名不一样的情况。
使用方式:
1、先定义resultMap,指定列名和属性的对应关系。
2、在<select>标签中把resultType替换为resultMap。
接口方法:List<MyStudent> selectMyStudent();
mapper文件:
<!--列名和属性名不一致的第一种方式:使用resultMap
1、先定义resultMap
2、在select标签中引用1定义的resultMap
-->
<!--定义resultMap
id:自定义名称,表示你定义的这个resultMap
type:javaleix的全限定名称
-->
<resultMap id="MyStudentMap" type="com.domain.MyStudent">
<!--列名和java属性的关系-->
<!--主键列,使用id标签
column:列名
property:java对象的属性名
-->
<id column="id" property="stuId"/>
<!--非主键字段使用result-->
以上是关于MyBatis笔记的主要内容,如果未能解决你的问题,请参考以下文章
markdown [mybatis参考]关于mybatis #mybatis的一些片段