MyBatis
三层架构
1、界面层(controller包 servlet)
2、业务逻辑层(service包):接收表示传递过来的数据,检查数据,计算业务逻辑,计算业务逻辑,调用数据访问层获取数据。
3、数据访问层(dao包)
三层对应的处理框架:
界面层——servlet——springmvc(框架)
业务逻辑层——service类——spring(框架)
数据访问层——dao类——mybatis(框架)
MyBatis框架概述
基于java的持久层框架。早期叫做ibatis,代码在github。
mybatis是sql映射框架:
1)sql mapper:sql映射
可以把数据库表中的一行数据,映射为一个java对象。一行数据可以看作是一个java对象。操作这个对象,就相当于操作表中的数据。
2)数据访问,对数据库进行增删改查
mybatis提供了哪些功能:
1、提供了框架Connection,Statement,ResultSet的能力,不用开发人员创建这些对象了
2、提供了执行sql语句的能力,不用你执行sql
3、提供了循环sql,把sql的结果转化为java对象,List集合的能力
4、提供了关闭资源的能力,不用你关闭Connection,Statement,ResultSet
开发人员提供sql语句
最后是:开发人员提供sql语句–mybatis处理sql–开发人员得到List集合或java对象(表中的数据)
基本步骤
1、加入依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<!--mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.9</version>
</dependency>
2、创建Dao接口
//接口操作Student表
public interface StudentDao {
//查询Student表的所有数据
public List<Student> selectStudents();
}
3、创建mapper文件,也叫做sql映射文件:写sql语句的,和接口中方法对应的sql语句
<?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">
<!--
namespace:必须有值,自定义的唯一字符串
推荐使用:dao 接口的全限定名称
--> <mapper namespace="org.example.domain.Student">
<!--
<select>: 查询数据, 标签中必须是 select 语句
id: sql 语句的自定义名称,推荐使用 dao 接口中方法名称,
使用名称表示要执行的 sql 语句
resultType: 表示结果类型的,是sql语句执行后得到的ResultSet,遍历这个ResultSet得到java对象的类型
值写的类型的全限定名称
-->
<select id="selectStudents" resultType="org.example.domain.Student">
<!--要执行的 sql 语句-->
select id,name,email,age from student order by id
</select>
</mapper>
<!--
sql映射文件:写sql语句的,mybatis会执行这些sql
1、指定约束文件
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
mybatis-3-mapper.dtd是约束文件的名称,扩展名是dtd的。
2、约束文件的作用: 限制,检查在当前文件中出现的标签,属性必须符合mybatis要求
3、mapper 是当前文件的根标签,必须的。
namespace:叫做命名空间,唯一值的,可以是自定义的字符串
要求你使用dao接口的全限定名称
4、在当前文件中,可以使用特定的标签,表示数据库的特定操作。
<select>:表示执行查询
<update>:表示更新数据库的操作,就是在<update>标签中 写的是update sql语句
<insert>:表示插入,放的是insert语句
<delete>:表示删除,执行的delete语句
-->
4、创建mybatis的主配置文件
1)连接数据库
2)指定mapper文件的位置
<?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>
<!--环境配置:数据库的连接信息
default:必须和某个environment的id值一样。
告诉mybatis使用哪个数据库的连接信息。也就是访问哪个数据库
-->
<environments default="mysql">
<!--id:数据源的名称-->
<environment id="mysql">
<!--
transactionManager:mybatis事务类型
type:JDBC(表示使用jdbc中的Connection对象的commit,rollback做事务处理)
-->
<transactionManager type="JDBC"/>
<!--数据源 dataSource:创建数据库 Connection 对象
type: POOLED 使用数据库的连接池
-->
<dataSource type="POOLED">
<!--连接数据库的四个要素-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ssm"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--一个mapper标签指定一个文件的位置
从类路径开始的路径信息 target/classes(类路径)
-->
<mapper resource="org/example/dao/StudentDao.xml"/>
</mappers>
</configuration>
<!--
mybatis的主配置文件:主要定义了数据库的配置信息,sql映射文件的位置
1、约束文件
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
mybatis-3-config.dtd约束文件的名称
2、configuration 根标签
-->
5、使用mybatis的对象SqlSession,通过他的方法执行sql语句
public class MyApp {
public static void main(String[] args) throws IOException {
//访问mybatis读取student数据
//1.定义mybatis主配置文件的名称,从类路径的根开始(target/classes)
String config = "mybatis.xml";
//2.读取这个config表示的文件
InputStream in = Resources.getResourceAsStream(config);
//3.创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//4.创建SqlSessionFactoryBuilder对象
SqlSessionFactory factory = builder.build(in);
//5.获取SqlSession对象,从sqlSessionFactory中获取sqlSession
SqlSession sqlSession = factory.openSession();
//6.指定要执行sql语句的标识。sql映射文件中的namespace+"."+标签id值
String sqlId = "org.example.domain.Student"+"."+"selectStudents";
//7.执行sql语句,通过sqlId找到语句
List<Student> studentList = sqlSession.selectList(sqlId);
//8.输出结果
//studentList.forEach(stu-> System.out.println(stu));
for (Student stu:studentList) {
System.out.println("查新的学生="+stu);
}
//9.关闭sqlSession对象
sqlSession.close();
}
}
输出日志
<!--settings:控制mybatis全局行为-->
<settings>
<!--设置mybatis输出日志-->
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
主要类的介绍
//1)Resources:mybatis中的一个类,负责读取主配置文件
InputStream in = Resources.getResourceAsStream(mybatis.xml);
//2) SqlSessionFactoryBuilder:创建SqlSessionFactory对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//创建SqlSessionFactoryBuilder对象
SqlSessionFactory factory = builder.build(in);
/*3)SqlSessionFactory:重量级对象,程序创建一个对象耗时比较长,使用资源比较多。在整个项目中,有一个就够用了。
SqlSessionFactory接口,接口实现类:DefaultSqlSessionFactory
SqlSessionFactor的作用:获取SqlSession对象。SqlSession sqlSession = factory.openSession();
方法说明:
1、openSession():无参数的,获取是非自动提交事务的SqlSession对象
2、openSession(boolean):openSession(true) 获取自动提交事务的SqlSession
openSession(false) 非自动提交的SqlSession对象
*/
//4)SqlSession:
//Sqlsession接口:定义了操作数据库的方法 例如: selectOne() selectList() insert() update() delete() commit() rollback()
//SqlSession接口的实现类 DefaultSqlSession
//使用要求:SqlSession对象不是线程安全的,需要在方法内部使用,在执行sql语句之前,使用openSession()获取SqlSession()对象,在执行完sql语句后,需要关闭它,执行SqlSession.close().这样能保证他的使用是线程安全的。
动态代理
package org.example;
import org.apache.ibatis.session.SqlSession;
import org.example.dao.StudentDao;
import org.example.domain.Student;
import org.example.uitls.MyBatisUtils;
import org.junit.Test;
import java.util.List;
public class TestMybatis {
@Test
public void testSelectStudents(){
/**
* 使用mybatis的动态代理机制,使用SqlSession.getMapper(dao接口)
* getMapper能获取dao接口对应的实现类对象
*/
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
//调用dao的方法执行数据库的操作
List<Student> students = dao.selectStudents();
for (Student stu:students){
System.out.println("学生="+stu);
}
}
@Test
public void testInsertStudent(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
Student student = new Student();
student.setId(1007);
student.setName("盾山");
student.setEmail("dunshan@qq.com");
int nums = dao.insertStudent(student);
sqlSession.commit();
System.out.println("添加的对象的数量:"+nums);
}
}
1.动态代理:使用SqlSession.getMapper(dao接口.class)获取这个dao接口的对象
2.传入参数:从java代码中把数据传入到mapper文件的sql语句中
1)ParameterType:写在mapper文件中的一个属性。表示dao接口中方法的参数的数据类型。
例如:StudentDao接口
public Student selectStudentById(Integer id);
2)一个简单类型的参数:
简单类型:mybatis把java的基本数据类型和String都叫简单类型
在mapper文件获取简单类型的一个参数的值,使用#{任意字符}
接口:public Student selectStudentById(Integer id);
mapper:select id, name, email, age from studentwhere id = #{studentId}
传参
1)多个参数,使用@Param命名参数
接口:pubilc List selectMulitParam(@Param(“myname”)String name,@Param(“myage”)Ingter age)
使用@Param(“参数名”) String name
mapper文件:
select
select * from student where name=#{myname} or age=#{myage}
/select
2)多个参数,使用对象,使用位置,使用Map
<select id="selectMultiObject" resultType="org.example.domain.Student">
select id,name,email,age from student where name = #{paramName} or age=#{paramAge}
</select>
<!--多个参数使用对象-->
<select id="selectMultiStudent" resultType="org.example.domain.Student">
select id,name,email,age from student where name = #{name} or age=#{age}
</select>
<!--多个参数使用位置-->
<select id="selectMultiPosition" resultType="org.example.domain.Student">
select id,name,email,age from student where name = #{arg0} or age=#{arg1}
</select>
<!--多个参数使用Map,使用语法#{map的key}-->
<select id="selectMultiByMap" resultType="org.example.domain.Student">
select id,name,email,age from student where name = #{myname} or age=#{age}
</select>
@Test
public void testSelectMultiObject(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
QueryParam param = new QueryParam();
param.setParamName("张三");
param.setParamAge(28);
List<Student> students = dao.selectMultiObject(param);
for (Student stu:students){
System.out.println("学生="+stu);
}
sqlSession.close();
}
@Test
public void testSelectMultiStudent(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
Student student = new Student();
student.setName("张三");
student.setAge(28);
List<Student> students = dao.selectMultiStudent(student);
for (Student stu:students){
System.out.println("学生="+stu);
}
sqlSession.close();
}
@Test
public void testSelectMultiPosition(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
List<Student> students = dao.selectMultiPosition("李四",20);
for (Student stu:students){
System.out.println("学生="+stu);
}
sqlSession.close();
}
@Test
public void testSelectMultiByMap(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
Map<String,Object> data = new HashMap<>();
data.put("myname","张三");
data.put("age",28);
List<Student> students = dao.selectMultiByMap(data);
for (Student stu:students){
System.out.println("学生="+stu);
}
sqlSession.close();
}
$和#
#:占位符,告诉 mybatis 使用实际的参数值代替。并使用 PrepareStatement 对象执行 sql 语句, #{…}代替sql 语句的“?”。这样做更安全,更迅速,通常也是首选做法。
** ∗ ∗ ∗ ∗ 字 符 串 替 换 , ∗ ∗ 告 诉 m y b a t i s 使 用 ** **字符串替换,**告诉 mybatis 使用 ∗∗∗∗字符串替换,∗∗告诉mybatis使用包含的“字符串”替换所在位置。使用 Statement 把 sql 语句和${}的
内容连接起来。主要用在替换表名,列名,不同列排序等操作。
: 可 以 替 换 表 明 或 者 列 名 , 你 能 确 定 数 据 是 安 全 的 。 可 以 使 用 :可以替换表明或者列名,你能确定数据是安全的。可以使用 :可以替换表明或者列名,你能确定数据是安全的。可以使用
$和#的区别:
1、#使用?在sql语句中做占位的,使用PreparedStatement执行sql,效率高
2、#能够避免sql注入,更安全
3、$不使用占位符,是字符串连接方式,使用Statement对象执行sql,效率低
4、$有sql注入的风险,缺乏安全性
5、$:可以替换表明或者列名
封装Mybatis输出结果
resultType
resultType: 执行 sql 得到 ResultSet 转换的类型,使用类型的完全限定名或别名。 注意如果返回的是集
合,那应该设置为集合包含的类型,而不是集合本身。resultType 和 resultMap,不能同时使用。
mybatis的输出结果:
mybatis执行了sql语句,得到java对象
1)resultType结果类型,指sql语句执行完毕后,数据转为的java对象,java类型是任意的
resultType结果类型的它值 1.类型的全限定名称 2.类型的别名,例如java.lang.Ingter别名是int
处理方式:
1.mybatis执行sql语句,然后mybatis调用类的无参数构造方法,创建对象
2.mybatis把ResultSet指定的列指附给同名的属性。
<select id="selectMultiPosition" resultType="org.example.domain.Student">
select id,name,email,age from student
</select>
对等的jdbc
ResultSet rs = executeQuery("select id,name,email,age from student")
while(rs.next()){
Student student = new Student;
student.setId(rs.getInt("id"));
student.setName(rs.getString("name"));
}
2)定义自定义类型的别名
1)在mybatis主配置文件中定义,使定义别名
2)可以在resultType中使用自定义别名
<!--定义别名-->
<typeAliases>
<!--
第一种方式:
可以指定一个类型一个自定义别名
type:自定义类型的全限定名称
alias:别名(短小,容易记忆的)
-->
<!--<typeAlias type="org.example.domain.Student" alias="stu"/>-->
<!--<typeAlias type="org.example.vo.ViewStudent" alias="vstu"/>-->
<!--
第二种方式:
<package> name是报名,这个包中的所有类,类名就是别名(类名不区分大小写)
-->
<package name="org.example.domain"/>
<package name="org.example.vo"/>
</typeAliases>
3)resultMap:结果映射,指定列名和java对象的属性对应关系。
1)你自定义的列值赋值给哪个属性
2)当你的列名和属性名不一样时,一定使用resultMap
resultMap和resultType不要一起用,二选一
模糊查询
<!--第一种like,java代码指定like的内容-->
<select id="selectLikeOne" resultType="org.example.domain.Student">
select id,name,email from student where name like #{name}
</select>
<!--第二种方式:在mapper文件中拼接like的内容-->
<select id="selectLikeTwo" resultType="org.example.domain.Student">
select id,name,email from student where name like "%" #{name} "%"
</select>
动态SQL
动态sql:sql的内容是变化的,可以根据条件获取到不同的sql语句。主要是where部分发生变化
动态sql的实现,使用的是mybatis提供的标签,,,
1)是判断条件的,
语法
部分sql语句
2)用来包含 多个的,当多个if有一个成立的,会自动增加一个where关键字,并去掉if中多余的and,or等。
3)循环java中的数组,list集合的。主要用在sql的in语句中
学生id是 1001,1002,1003的三个学生
select * from student where id in(1001,1002,1003)
collection:表示接口中方法参数的类型,如果是数组使用array,如果是list集合使用list
item:自定义的,表示数组和集合成员的变量
open:循环开始时的字符
close:循环结束时的字符
separator:集合成员之间的分隔符
<!--if
<if test="使用参数java对象的属性值作为判断条件,语法 属性=xxx值"></if>
-->
<select id="selectStudentIf" resultType="org.example.domain.Student">
select id,name,age,email from student
where 1=1
<if test="name !=null and name !='' ">
name = #{name}
</if>
<if test="age > 0">
and age> #{age}
</if>
</select>
<!--
where:<where><if><if>...</where>
-->
<select id="selectStudentWhere" resultType="org.example.domain.Student">
select id,name,email,age from student
<where>
<if test="name !=null and name !='' ">
name = #{name}
</if>
<if test="age > 0">
or age= #{age}
</if>
</where>
</select>
<!--foreach使用1,List<Integer>-->
<select id="selectForeachOne" resultType="org.example.domain.Student">
select * from student where id in
<foreach collection="list" item="myid" open="(" close=")" separator=",">
#{myid}
</foreach>
</select>
<!--foreach使用2,List<Integer>-->
<select id="selectForeachTwo" resultType="org.example.domain.Student">
select * from student where id in
<foreach collection="list" item="stu" open="(" close=")" separator=",">
#{stu.id}
</foreach>
</select>
4)sql代码片段,就是复用一些语法
步骤:
1.先定义 sql语句,表明,字段等
2.再使用,
Mybatis配置文件
1.数据库的属性配置文件:把数据库连接信息放到一个单独的文件中。和mybatis主配置文件分开。
目的是便于修改,保存,处理多个数据库的信息。
1)在resources目录中定义一个属性配置文件,xxx.properties,例如jdbc.properties
在属性配置文件中,定义数据,格式是key=value
key:一般使用 . 做多级目录的
例如 jdbc.mysql.driver
2)在mybatis的主配置文件,使用指定文件的位置
在需要使用值的地方${key}
2.mapper文件,使用package指定路径
<mappers>
<!--第一种方式:指定多个mapper文件-->
<!-- <mapper resource="org/example/dao/StudentDao.xml"/>-->
<!-- <mapper resource="org/example/dao/OrderDao.xml"/>-->
<!--第二种方式:使用包名
name:xml文件(mapper文件) 所在的包名,这个包中的所有xml文件一次都能加载给mybatis
使用package的要求:
1.mapper文件名称需要和接口名称一样,区分大小写的一样
2.mapper文件和dao接口需要在同一目录
-->
<package name="org.example.dao"/>
</mappers>
扩展
PageHelper做数据分页
复习
什么是动态代理:
mybatis帮你创建dao接口的实现类,在实现类中调用SqlSession的方法执行sql语句
使用动态代理的方式:
1、获取SqlSession对象,SqlSessionFactory.openSession()
2、使用getMapper方法获取某个接口的对象,sqlSession.getMapper(接口.class)
3、使用dao接口的方法,调用方法就执行了mapper文件中的sql语句
使用动态代理方式的要求:
1、dao接口和mapper文件放在一起,同一个目录
2、dao接口和mapper文件名称一致
3、mapper文件中的namespace的值是dao接口的全限定名称
4、mapper文件中的,,,等的id是接口中方法的名称
5、dao接口中不要使用重载方法,不要使用同名的,不同参数的方法
理解参数:
从java代码中把实际的值传入到mapper中
1、一个简单类型的参数:#{任意字符}
2、多个简单类型的参数@Param(“自定义名称”)
3、使用一个java对象,对象的属性值作为mapper文件找到参数,#{java对象的属性名称}
4、使用参数的位置,语法#{arg0},#{arg1},mybatis3.4之前的版本,使用#{0},#{1}
5、使用Map作为参数,#{map的key}
#和$的区别:
1、#是占位符,表示列值的,放在等号右侧
2、$占位符,表示字符串的连接,把sql语句连接成一个字符串
3、#占位符使用的jdbc指定PreparedStatement对象执行SQL语句,效率高,没有sql注入的风险
4、$使用的是Statement对象执行sql,效率低,有sql注入的风险
mybatis返回结果:
resultType——表示sql语句的执行结果,转为的java对象的类型:
1.类型的全限定名称
2.别名:
在mybatis主配置文件定义别名:
①使用
②使用:类名就是别名
resultMap——自定义列名和java对象的属性名对应关系
列名和属性名不一样解决方式:
1.使用列名
2.使用resultMap
like:
1.在java代码中指定like的内容
2.在mapper中拼接like
动态sql:
1.根据条件,能够得到不同的sql语句,使用mybatis的标签,例如if,where,foreach等
2.if:判断条件的,条件为true,就会把if之间的sql加入到主sql之后
3.where:标签里面是多个if,如果有一个if判断为true,会在sql的后面加入where关键字,会去掉无用的and,or等字符
4.foreach:循环数组,list集合
5.sql代码片段:复用部分sql语句的
mybatis主配置文件:
1.mybatis属性配置文件的使用
2.在mybatis文件的位置
PageHelper:
1.功能:实现多种数据库的分页,mysql就是代替limit语句的
2.使用步骤
1)加入maven依赖
2)在mybatis主配置文件加入plugin
3)在你的查询方法之前,加入PageHelper方法调用