一 框架概述
1.三层架构
视图层——和用户打交道,接收用户访问参数,显示处理结果——SpringMVC
业务层——接受了界面层传递的数据,计算逻辑,调用数据库,获取数据——Spring
持久层——访问数据库,执行数据的查询、修改、删除等等——MyBatis
2.Mybatis框架
主要功能: 执行数据库的操作,完成对数据的增删改查;看做是jdbc的升级版
特点: ①执行数据库的增删改查,可以只关心sql语句如何编写。②sql mapper: sql映射,mybatis可以把表中的数据转为一个java对象,把表和java对象对应起来。
二 Mybatis使用步骤
1.实体类:使用实体类表示表中的数据,表中的一行数据就相当于是一个实体类对象
2.定义dao接口:定义方法,方法表示要执行的数据操作, 方法名称应该和mapper文件中的id一样
3.定义mapper文件,是一个xml文件,编写sql语句
4.定义mybatis主配置文件:1)定义数据源DataSource;2)指定mapper文件的位置
5.mybatis执行sql语句的核心对象:SqlSession, 使用SqlSession的方法执行sql语句,使用SqlSessionFactory的openSession()方法获取SqlSession对象
注意:
<--写sql语句的文件,mybatis会执行这些文件-->
<?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叫做命名空间,唯一值的,可以是任意字符串。规范要求使用DAO接口的全限定名称。
-->
<mapper namespace="dao接口的全限定名称">
<!--特定标签执行特定操作:
<select/>:查询
<update/>:修改
<insert/>:增加
<delete/>:删除
-->
<!--id:你要执行的sql语法的唯一标识。mybatis会根据id值来找到要执行的sql语句。可以自定义,但最好写成接口中对应的方法名。
resultType:sql语句执行后得到了ResultSet,遍历ResuSet每一行数据得到的Java对象名称。即在步骤3中创建的实体类的全限定名称-->
<select id="接口中的方法名称" resultType="结果类型">
select * from 表 where id = #{id}
</select>
</mapper>
实例1:
实现步骤:
1.新建student表
int id,varchar name,varchar email,int age
2.加入maven的mybatis坐标,mysql驱动的坐标
<dependencies>
<!--mybatis的依赖-->
<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>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory><!--所在的目录-->
<includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
3.创建实体类,Student–保存表中一行数据的
public class Student {
private Integer id;
private String name;
private String email;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
", age=" + age +
'}';
}
}
4.创建持久层的dao接口,定义操作数据库的方法
public interface StudentDao {
//查询student表的所有数据
public List<Student> selectStudents();
//插入方法
//student:表示要插入数据库的数据
//int: 表示执行insert操作后,影响数据库的行数
public int insertStudent(Student student);
}
5.创建一个mybatis使用的配置文件
叫做sql映射文件:写sql语句的,一般一个表一个sql映射文件
这个文件是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.bjpowernode.dao.StudentDao">
<!--查询操作-->
<select id="selectStudents" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student order by id
</select>
<!--插入操作-->
<insert id="insertStudent">
insert into student values(#{id},#{name },#{email},#{age})
</insert>
</mapper>
6.创建mybatis的主配置文件:
一个项目就一个主配置文件。
主配置文件提供了数据库的连接信息和sql映射文件的信息
<?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>
<environments default="mydev">
<environment id="mydev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
<property name="username" value="root"/>
<property name="password" value="******"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
</mappers>
</configuration>
7.MyBatisUtils 类
public class MyBatisUtils {
private static SqlSessionFactory factory = null;
static {
String config = "mybatis.xml";
try {
InputStream in = Resources.getResourceAsStream(config);
//创建SqlSessionFactory对象,使用SqlSessionFactoryBuild
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;
}
}
8.创建使用mybatis类
通过mybatis访问数据库
public class MyApp {
public static void main(String[] args) throws IOException {
//访问mybatis读取student数据
//1.定义mybatis主配置文件名称,从类路径跟开始
String config = "mybatis.xml";
//2.读取config表示的文件
InputStream in = Resources.getResourceAsStream(config);
//3.创建sqlSessionFactoryBuilder
SqlSessionFactoryBuilder bulider = new SqlSessionFactoryBuilder();
//4.创建sqlSessionFactory对象
SqlSessionFactory factory = bulider.build(in);
//5.【重要】获取sqlSession对象,从sqlSessionFactory中获取sqlSession
SqlSession sqlSession = factory.openSession();
//6.【重要】指定要执行的SQL语句的标识(namespace.id)
String sqlId = "com.bjpowernode.dao.StudentDao.selectStudents";
//7.执行语句
List<Student> studentList = sqlSession.selectList(sqlId);
//8.输出结果
studentList.forEach( stu ->System.out.println(stu));
//9.关闭sqlsession对象
sqlSession.close();;
}
}
8.输出结果,此处显示为查询操作
实例2: 创建dao接口实现类
public class StudentDaoImpl implements StudentDao {
@Override
public List<Student> selectStudents() {
//获取SqlSession对象
SqlSession sqlSession = MyBatisUtils.getSqlSession();
String sqlId = "com.bjpowernode.dao.StudentDao.selectStudents";
//执行sql语句,使用SqlSession的方法
List<Student> students = sqlSession.selectList(sqlId);
//关闭
sqlSession.close();
return students;
}
测试代码:
public class TestMybatis {
@Test
public void testSelectStudent(){
StudentDao dao = new StudentDaoImpl();
/**
* List<Student> studentList = dao.selectStudents();
* 1.dao对象,类型是StudentDao,全限定名称为:com.bjpowernode.dao.StudentDao
* 全限定名称和namespace是一样的
* 2.方法名称,selectStudents ,这个方法就是mapper文件中的id
* 3.通过dao中方法的返回值也可以确定mybatis要调用的sqlsession的方法
* 如果返回值是List,调用的是sqlsession.selectList()方法
* 如果返回值是int 或者其他非List,看mapper文件中的标签<insert>,<update>
* 就会调用sqlsession的insert,update等方法
*
*
* mybatis的动态代理:mybatis根据dao的方法调用,获取执行sql语句的信息
* mybatis根据你的dao接口,创建出一个dao接口的实现类,并创建这个类的对象
* 完成sqlsession调用方法,访问数据库
* */
List<Student> studentList = dao.selectStudents();
for (Student stu:studentList){
System.out.println(stu);
}
}
三 MyBatis 框架 Dao 代理
1.Dao 代理实现 CURD
(1) 去掉 Dao 接口实现类
(2) getMapper 获取代理对象
只需调用 SqlSession 的 getMapper()方法,即可获取指定接口的实现类对象。该方法的参数为指定 Dao接口类的 class 值。
SqlSession session = factory.openSession();
StudentDao dao = session.getMapper(StudentDao.class);
使用工具类:
StudentDao studentDao =MyBatisUtil.getSqlSession().getMapper(StudentDao.class);
(3) 使用 Dao 代理对象方法执行 sql 语句
2.mybatis的传参数
1.dao方法有一个简单类型的参数,在mapper文件中,使用#{任意字符串}
2.使用@Param注解给参数命名, 在mapper文件,使用#{自定义的名称}
3.使用java对象传参, 在mapper文件中, 使用#{java对象属性名称}
4.使用参数的位置, 在mapper文件,#{arg位置值,从0开始}
5.使用map, #{map的key}
public interface StudentDao {
/*
* 一个简单类型的参数
* 简单类型:mybatis把java的基本数据类型和String都叫简单类型
* 在mapper文件获取简单类型的一个参数的值,使用#{任意字符}
* */
public Student selectStudentById(Integer id);
/*
* 多个参数:命名参数,在形参定义的前面加@param("自定义参数名称")
* */
List<Student> selectMultiParam(@Param("myname") String name,
@Param("myage") Integer age);
/*
* 多个参数,使用java对象作为接口中方法的参数
* */
List<Student> selectMultiObject(QueryParam param);
List<Student> selectMultiStudent(Student student);
}
<?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.bjpowernode.dao.StudentDao">
/*
parameterType : dao接口中方法参数的数据类型
parameterType的值是java的数据类型全限定名称或者是mybatis定义的别名
不是强制的,一般可以不写
使用#{}之后,mybatis执行sql是使用jdbc中的preparedStatement对象
由mybatis执行下面的代码:
1.mybatis创建Connection,preparedStatement对象
String sql = "select id,name,email, age from student where id = ?";
preparedStatement pst = conn.preparedStatement(sql);
pst.setInt(1,1001);
2.执行sql封装成resultType = "com.bjpowernode.domain.Student"这个对象
ResultType rs = ps.executeQuery();
Student student = null;
while(rs.next()){
//从数据库取表的一行数据,存到一个java对象属性中
student = new Student();
student.setId(rs.getInt("id"));
student.setName(rs.getString("name"));
student.setEmail(rs.getInt("email"));
student.setAge(rs.getInt("age"));
}
return student;
*/
<select id="selectStudentById" parameterType="java.lang.Integer" resultType="com.bjpowernode.domain.Student">
select id,name,email, age from student where id = #{id}
</select>
//<!--多个参数使用param命名-->
<select id="selectMultiParam" resultType="com.bjpowernode.domain.Student">
select id,name,email, age from student where name = #{myname} or age = #{myage}
</select>
/*多个参数,使用对象的属性值,作为参数实际值
使用对象完整语法:
#{属性名,javaType=类型名称,JdbcType=数据类型} 很少用
javaType:java中的属性数据类型
JdbcType:数据库中的数据类型
eg:#{paramName,javaType=java.lang.String,JdbcType=VARCHAR}
一般使用简化方式:
#{属性名} javaType,JdbcType不用提供,mybatis反射获取
*/
<select id="selectMultiObject" resultType="com.bjpowernode.domain.Student">
select id,name,email, age from student where name = #{paramName} or
age = #{paramAge}
</select>
<select id="selectMultiStudent" resultType="com.bjpowernode.domain.Student">
select id,name,email, age from student where name = #{name} or
age = #{age}
</select>
</mapper>
3.#和$区别
1.#是占位符,使用?做占位符合,mybatis内部使用PreparedStatement对象执行sql语句,效率高
2.#表示列的值, 一般是放在等号的右侧使用
3.$是字符串代理连接, 把sql语句和
位置的值连接在一起
4.
{}位置的值连接在一起 4.
位置的值连接在一起4.所表示的内容是原样替换的
5.
使用的
s
q
l
语句,
m
y
b
a
t
i
s
使用的是
S
t
a
t
e
m
e
n
t
对象执行
s
q
l
6.
使用的sql语句,mybatis使用的是Statement对象执行sql 6.
使用的sql语句,mybatis使用的是Statement对象执行sql6.一般是替换表名,列名, 部分sql语句的
4.MyBatis中主要对象的介绍
**Resources:**负责读取著配置文件
**SqlSessionFactoryBuilder:**负责创建SqlSessionFactory对象
**SqlSessionFactory:**重量级对象(创建对象耗时长,占用资源多,整个项目中有一个就够用了),是一个接口,实现类:DefaultSqlSessionFactory。用于获取sqlSession对象。
方法说明:
1) openSession() 无参数,获取非自动提交事务的sqlSession对象。
2)openSession(boolean autoCommit)参数为true,获取自动提交事务的sqlSession对象。
**SqlSession:**接口,定义了操作数据库的方法。类DefaultSqlSession对这些方法进行了实现。SqlSession不是线程安全的,需要在方法内部使用,使用之前通过SqlSessionFactory的openSession获取,使用之后通过sqlsession.close()关闭,以保证线程安全。
5.封装 MyBatis 输出结果与模糊like
1.dao接口
//返回一个map
Map<Object,Object> selectMapById(Integer id);
//使用resultMap定义映射关系
List<Student> selectAllStudents();
//列名和属性名不一致1
List<myStudent> selectMyStudents();
//列名和属性名不一致2
List<myStudent> selectDiffColProperty();
//第一种模糊查询,在java代码中指定like的内容
List<Student> selectLikeOne(String name);
//第二种like,在mapper文件中拼接like的内容
List<Student> selectLikeTwo(String name);
2.mapper映射文件
/*
selectMapById返回map:
列名是map的key,列值是map的value
只能返回一条记录,多了就会报错
*/
<select id="selectMapById" resultType="map">
select id,name from student where id = #{stuid}
</select>
/*
使用resultMap:
1.先定义resultMap
2.在select标签引用定义的resultMap
*/
//定义resultMap:id,自定义名称;type,java全限定名称
<resultMap id="studentMap" type="com.bjpowernode.domain.Student">
<!--定义列名和java属性的关系-->
<!--主键列 id标签-->
<id column="id" property="id"/>
<!--非主键列 result标签-->
<result column="name" property="name"/>
<result column="email" property="email"/>
<result column="age" property="age"/>
</resultMap>
<select id="selectAllStudents" resultMap="studentMap">
select id,name,email,age from student
</select>
<!--列名和属性名不一致:第一种方式-->
<resultMap id="myStudentMap" type="com.bjpowernode.domain.myStudent">
<!--定义列名和java属性的关系-->
<!--主键列 id标签-->
<id column="id" property="stuid"/>
<!--非主键列 result标签-->
<result column="name" property="stuname"/>
<result column="email" property="stuemail"/>
<result column="age" property="stuage"/>
</resultMap>
<select id="selectMyStudents" resultMap="myStudentMap">
select id,name,email,age from student
</select>
<!--
列名和属性名不一致:第二种方式
resultType默认原则:同名的列值赋给同名的属性 ,使用列别名as
-->
<select id="selectDiffColProperty" resultType="com.bjpowernode.domain.myStudent">
select id as stuid,name as stuname,email as stuemail,age as stuage from student
</select>
<!--第一种like-->
<select id="selectLikeOne" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name like #{name}
</select>
<!--第二种like,在mapper文件中拼接like的内容-->
<select id="selectLikeTwo" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name like "%" #{name} "%"
</select>
四 动态sql
通过在mapper中,使用标签,通过条件生成不同的sql语句,主要是控制where 条件部分
1、: 当条件为true,把sql语句加入到主sql中
2、 :where里面是if, 当if条件有一个满足,在主sql语句加入 where 关键字和条件
3、:1.循环基本类型,例如List;2.循环对象类型,例如List
实例3:
1.dao接口
public interface StudentDao {
//动态sql,使用java对象作为参数
List<Student> selectStudentIf(Student student);
//where的使用
List<Student> selectStudentWhere(Student student);
//foreach 用法1
List<Student> selectForeachOne(List<Integer> idlist);
//foreach 用法2
List<Student> selectForeachTwo(List<Student> stulist);
}
2.mapper映射
<?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.bjpowernode.dao.StudentDao">
//if
<select id="selectStudentIf" resultType="com.bjpowernode.domain.Student">
select id,name,email, age from student
where
/*
如果没有赋值name,会出现语法错误,下边语句多了一个or,可以给where后边加 id>0
虽然没有意义但是可以避免SQL语法错误
where 也可以解决这个问题
*/
<if test="name != null and name != '' ">
name = #{name}
</if>
<if test="age > 0 ">
or age > #{age}
</if>
</select>
//where的使用
<select id="selectStudentWhere" resultType="com.bjpowernode.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>:
collection:表示接口中的方法参数的类型, 如果是数组使用array , 如果是list集合使用list
item:自定义的,表示数组和集合成员的变量
open:循环开始是的字符
close:循环结束时的字符
separator:集合成员之间的分隔符
*/
<select id="selectForeachOne" resultType="com.bjpowernode.domain.Student">
select * from student where id in
<foreach collection="list" item="myid" open="(" close=")" separator=",">
#{myid}
</foreach>
</select>
//selectForeachTwo
<select id="selectForeachTwo" resultType="com.bjpowernode.domain.Student">
select * from student where id in
<foreach collection="list" item="stu" open="(" close=")" separator=",">
#{stu.id}
</foreach>
</select>
</mapper>
五 Mybatis配置文件
1.settings中可以配置日志
2.配置别名
3.dataSource:配置数据源
4.配置mapper文件的位置
5.使用属性配置文件(.properties)
六 PageHelper
一个插件,给sql语句增加分页功能的。 在我们的sql语句之后,通过插件加入 limit这样的语句
使用步骤:
1.加入依赖
2.在mybatis主配置文件中,加入plugin
3.在你的查询方法之前加入 PageHelper.startPage(第一页,每页几行数据)