Mybatis
1.1常用框架
MVC框架:其实就是简化了Serviet的开发步骤
流行框架:1.Struts2
2.SpringMVC
持久层框架:完成数据库操作的框架
1.appache DBUtils
2.Hibernate
3.Spring JPA
4.MyBatis
胶水框架:Spring
SSM Spring+SpringMVC+Mybatis
1.2Mybatis介绍
mybatis是一个半自动的ORM框架
ORM (Object Relational Mapping)对象关系映射,将Java中的一个对象与数据表中一行记录——对应。
ORM框架提供了实体类与数据表的映射关系,通过映射文件的配置,实现对象的持久化(将对象保存到数据表中)。
mybatis的前身是ibatis
mybatis特点:
支持自定义sql,存储过程
对原有的JDBC进行了封装,几乎消除了所有JDBC代码,让开发者只需关注sQL本身
支持XML和注解配置方式自定完成ORM操作,实现结果映射,就是对象的属性和数据表列的对应关系
一.Mybatis部署
1创建Maven项目
1.java
2.web工程
2在项目中添加Mybatis依赖
1.在pom.xml中添加依赖
2.mybatis
<!-- mysql驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.27</version> </dependency> <!-- mybatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> </dependency> </dependencies>
添加mybatis文件
创建自定义模板mybatis-config.xml
在resources中创建mybatis-config.xml
在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> <!-- 在environments配置奇偶数据库连接信息--> <!-- 在environments标签中可以配置多个encvieronments,每个encvieronments可以配置一套数据库连接信息 --> <!-- default属性,用来指定使用哪个environment标签--> <environments default="mysql"> <environment id="mysql"> <!-- transactionManager 用于配置数据库管理方式--> <transactionManager type="JDBC"></transactionManager> <!-- dataSource用于配置数据库连接信息--> <dataSource type="POOLED"> <property name="drive" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/testkc? characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowMultiQueries=true"/> <property name="username" value="root"/> <property name="passworld" value="123456"/> </dataSource> </environment> </environments> </configuration>
二.Mybatis框架使用
2.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 );
2.2创建实体类
Student.java
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; @Data//时间构造器 @AllArgsConstructor//全餐构造器 @NoArgsConstructor//无参构造器 @ToString//重写构造器 public class Student { private int stuID; private String stuNum; private String stuName; private String stuGender; private int stuAge; }
2.3创建DAO接口,定义操作方法StydentDAO
public interface StudentDAO { public int insertStudent(Student student); public int deleteStudent(Student stuNum); }
2.4创建DAO接口的映射文件
1.在resources目录下,新建名为mappers文件夹
2.在mappers中新建名为StudentMapper.xml的映射文件(根据模板创建)
3.在映射文件中对DAO中定义的方法进行实现:
<?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文件相当于DA0接口的‘实现类’,namespace属性要指定`实现DAO接口的全限定名 --> <mapper namespace="com.hr.dao.StudentDAO"> <!-- id对应方法名 parameterType对应定实体类的路径--> <insert id="insterStudent" parameterType="com.hr.pojo.Student"> insert into tb_students(stu_num,stu_name,stu_gender,stu_age) values (#{stuNum},#{stuName},#{stuGender},#{stuAge}) </insert> <delete id="deleteStudent"> delete from tb_students where stu_num=#{stuNum} </delete> </mapper>
3.5将映射文件添加到主配置文件中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> <!-- 在environments配置奇偶数据库连接信息--> <!-- 在environments标签中可以配置多个encvieronments,每个encvieronments可以配置一套数据库连接信息 --> <!-- <! -- default属性,用来指定使用哪个environment标签–>--> <environments default="mysql"> <environment id="mysql"> <!-- transactionManager 用于配置数据库管理方式--> <transactionManager type="JDBC"></transactionManager> <!-- dataSource用于配置数据库连接信息--> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/testkc?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC&allowMultiQueries=true"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <!-- 添加的映射文件--> <mappers> <mapper resource="mappers/StudentMapper.xml"></mapper> </mappers> </configuration>
三.单元测试
3.1添加单元测试的依赖
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.9</version> <scope>test</scope> </dependency>
3.2创建单元测试类
在被测试类后面alt+insert---选择Test
public interface StudentDAO { public int insertStudent(Student student); public int deleteStudent(Student stuNum); }
3.3配置连接数据库 并实现增加操作
package com.hr.dao; import com.hr.pojo.Student; 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 java.io.InputStream; public class StudentDAOTest { @org.junit.Test public void insertStudent() { try { //加载mybatis配置文件 InputStream is= Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder(); //会话连接工厂 SqlSessionFactory factory=builder.build(is); //代表与数据库的连接 SqlSession sqlSession=factory.openSession(); //通过连接获得DAO对象 StudentDAO studentDAO=sqlSession.getMapper(StudentDAO.class); //测试StudentDAO中得方法 int i=studentDAO.insertStudent(new Student(0,"1001","张三","男",31)); //添加事务管理需要手动提交 sqlSession.commit(); System.out.println(i); }catch (Exception e){ e.printStackTrace(); } } @org.junit.Test public void deleteStudent() { } }
四.mybatis的CRUD操作(增删改查)
案例学生信息的曾山查改
5.1添加操作
略
5.2删除操作
根据学号删除学生信息
在StudentDAO中定义删除方法
public interface StudentDAO { public int insertStudent(Student student); public int deleteStudent(Student stuNum); }
5.3.在StudentMapper.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文件相当于DA0接口的‘实现类’,namespace属性要指定`实现DAO接口的全限定名 --> <mapper namespace="com.hr.dao.StudentDAO"> <!-- id对应方法名 parameterType对应定实体类的路径--> <insert id="insertStudent" parameterType="com.hr.pojo.Student"> insert into tb_students(stu_num,stu_name,stu_gender,stu_age) values (#{stuNum},#{stuName},#{stuGender},#{stuAge}) </insert> <delete id="deleteStudent"> delete from tb_students where stu_num=#{stuNum} </delete> </mapper>
4.4在StdentDAO的测试类中添加测试方法
StdentDAOTest
package com.hr.dao; import com.hr.pojo.Student; import com.sun.deploy.util.SessionState; 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 java.io.IOException; import java.io.InputStream; import java.io.Reader; public class StudentDAOTest { @org.junit.Test public void insertStudent() { try { //加载mybatis配置文件 InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //会话连接工厂 SqlSessionFactory factory = builder.build(is); //代表与数据库的连接 SqlSession sqlSession = factory.openSession(); //通过连接获得DAO对象 StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class); //测试StudentDAO中得方法 int i = studentDAO.insertStudent(new Student(0, "1001", "张三", "男", 31)); //添加事务管理 sqlSession.commit(); System.out.println(i); } catch (Exception e) { e.printStackTrace(); } } @org.junit.Test public void testDeleteStudent() { try { //以一个输入流的方式获取配置文件 InputStream is=Resources.getResourceAsStream("mybatis-config.xml"); // SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); // SqlSessionFactory表示Mybatis的会话工厂 SqlSessionFactory factory = builder.build(is); //SqlSession表示Mybatis,数据之间的会话,通过工厂方法设计模式 SqlSession sqlSession = factory.openSession(); //通过SqlSession对象调用getMapper方法获取DAO接口对象 StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class); int i=studentDAO.deleteStudent("1001"); //提交事务方法 sqlSession.commit(); System.out.println(i); } catch (Exception e) { e.printStackTrace(); } } }
4.6添加更改操作
在xml映射文件中编写更改语句
根据stu—num更改学生信息
<update id="updateStudent"> update tb_students set stu_name=#{stuName},stu_gender=#{stuGender}, stu_age=#{stuAge} where stu_num=#{stuNum} </update>
4.6编写实现update方法
testUpdaeStudent方法
@Test public void testUpdateStudent() throws IOException { InputStream is=Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder(); //创建工厂模式 SqlSessionFactory factory=builder.build(is); //通过会话获取DAO对象 SqlSession sqlSession=factory.openSession(); //测试StudentDAO中得方法 StudentDAO studentDAO=sqlSession.getMapper(StudentDAO.class); int i=studentDAO.updateStudent(new Student(0,"1001","李四","女",18)); sqlSession.commit(); System.out.println(i); }
4.7实现查询方法
在xml映射文件中编写查询语句
<!-- 第一种方式--> <!-- <select id="listStudent" resultType="com.hr.pojo.Student" resultSets="java.util.List">--> <!-- select sid as stuID ,stu_num stuNum,stu_name stuName,stu_gender stuGender,stu_age stuAge from tb_students--> <!-- </select>--> <!-- 查询方法的第二种方式 resultMap id="" id可以随便起名字 type对象实体类的路径--> <!-- resultMap标签用于定义实体类与数据映射表达映射关系(ORM)--> <resultMap id="studentMap" type="com.hr.pojo.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> <!--resultMap用于应用一个实体类的映射关系,当配置了resultMap之后,resultType就可以省略--> <select id="listStudent" resultMap="studentMap"> select sid,stu_num,stu_name,stu_gender,stu_age from tb_students </select>
4.6编写实现ListStudent方法
testListStudent方法
@Test public void testListStudent() throws IOException { 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.listStudent(); sqlSession.commit(); for (Student stu:list){ System.out.println(stu); } }
4.7-查询一条操作
根据学生id查询一个学生的信息
在StudentDAO定义方法
public Student quertStudent(String stuNum);
在xml映射文件中编写查询语句
<resultMap id="studentMap" type="com.hr.pojo.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="quertStudent" resultMap="studentMap"> select sid,stu_num,stu_name,stu_gender,stu_age from tb_students where stu_num=#{stuNum} </select>
在测试类 StudentDAOTest中编写查询方法
@Test public void testQuertStudent() throws Exception{ 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); Student student=studentDAO.quertStudent("1003"); sqlSession.commit(); System.out.println(student); }
4.8查询总记录数
在接口中 StudentDAO中定义方法
public int count();
在xml文件中配置查询语句
<!--统计数据条数 需要声明类型 resultType="int"--> <select id="count" resultType="int"> select count(1) from tb_students </select>
在测试类里面实现方法
@Test public void count() throws Exception{ 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); int i=studentDAO.count(); sqlSession.commit(); System.out.println(i); }
4.9分页查询-多参数查询
分页查询(参数 start , pageSize)
在Student中定义操作方法,如果方法有多个参数,使用@Param注解声明参数的别名
//分页查询@Param 起别名 public List<Student> listStudentByPage(@Param("start") int start, @Param(("pageSize")) int pageSize);
在StudentMapper.xml中配置时使用#{别名}获取指定的参数
<resultMap id="studentMap" type="com.hr.pojo.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> <!-- 分页查询也可以用 limit #(agr0),#{arg1} 或者limit #(parm1),#{pageSize}--> <select id="listStudentByPage" resultMap="studentMap"> select sid,stu_num,stu_name,stu_gender,stu_age from tb_students limit #{start},#{pageSize} </select>
社意如果DAQ操作方法没有通过@Param指定参数别名,在SQ.中也可以通过 arga,arg1. ..或者param1 , param2 ....获取婺数
5.10添加操作回填生成的主键
StudentMapper.xml
<!-- useGeneratedKeys设置添加操作是否需要回填生成的主键--> <!-- keyProperty设置回填的主键值赋值到参数对象的哪个属情--> <insert id="insertStudent" parameterType="com.hr.pojo.Student" useGeneratedKeys="true" keyProperty="stuID" > insert into tb_students(stu_num,stu_name,stu_gender,stu_age) values (#{stuNum},#{stuName},#{stuGender},#{stuAge}) </insert>
五.mybatis工具类的封装
MybatisUtils
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 java.io.IOException; import java.io.InputStream; public class MybatisUtils { //封装会话工厂 private static SqlSessionFactory factory; //添加线程锁 //在进行对象的跨层传递的时候,使用ThreadLocal可以避免多次传递,打破层次间的约束 private static final ThreadLocal<SqlSession> local=new ThreadLocal<SqlSession>(); //静态代码块 任何类启动时首先自动加载静态代码块 static { //加载mybatis配置文件 InputStream is = null; try { is = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //会话连接工厂 factory = builder.build(is); } catch (IOException e) { e.printStackTrace(); } } //封装factory方法 public static SqlSessionFactory getFactory(){ return factory; } //封装sqlSession会话 public static SqlSession getSqlSession() throws IOException { SqlSession sqlSession=local.get(); if (sqlSession==null){ sqlSession=factory.openSession(); local.set(sqlSession); } return sqlSession ; } // 关闭Sqlsession public static void close(){ SqlSession sqlSession=locol.get(); if (sqlSession !=null){ sqlSession.close(); locol.set(null); } } //使用泛型封装getMapper public static <T extends Object>T getMapper(Class<T> c) throws IOException { SqlSession sqlSession=getSqlSession(); return sqlSession.getMapper(c); } }
六.事务管理
增删改都需要提交事务
SqlSession对象的作用
1.get.Mapper(DAO.class)获取Mapper(DAO接口的实例 )(也就是映射文件)
2.事务管理
当获取Session对象时就开启了事务
7.1手动管理事务
sqlSession.commit();提交事务
sqlSession.rollback();事务回滚
@org.junit.Test public void insertStudent() throws IOException { //1.代表与数据库的连接 当我们获取sqlSession对象时,就默认开启了事务 SqlSession sqlSession = MybatisUtils.getSqlSession(); try{ //通过会话获得DAO对象 StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class); //测试StudentDAO中的方法 Student student=new Student(0, "1006", "懊悔", "男", 42); int i=studentDAO.insertStudent(student); //测试StudentDAO中得方法 System.out.println(student); //2当操作完成并完成之后 需要手动提交事务管理 sqlSession.commit(); }catch (Exception e){ //3当操作出现异常时,调用rollback方法 进行回滚 sqlSession.rollback(); } }
7.2自动提交事务
//通过SqLSessionFactory 调HjopenSession方法获取SqLSession对象时,可以通过参数设置事务是否自动提交
// 如果参数设置为true,表示自定提交事务:factory.openSession(true);
//如果参数设置为false,或者不设置参数,表示手动提交:factory .openSession() ; /factory.openSession(false);
MybatisUtils优化
1.给封装SqlSession方法添加了一个boolean isAutoCommit 参数
2.获取getMapper的时候传了一个true
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 java.io.IOException; import java.io.InputStream; public class MybatisUtils { //封装会话工厂 private static SqlSessionFactory factory; //添加线程锁 //在进行对象的跨层传递的时候,使用ThreadLocal可以避免多次传递,打破层次间的约束 private static final ThreadLocal<SqlSession> local=new ThreadLocal<SqlSession>(); //静态代码块 任何类启动时首先自动加载静态代码块 static { //加载mybatis配置文件 InputStream is = null; try { is = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //会话连接工厂 factory = builder.build(is); } catch (IOException e) { e.printStackTrace(); } } //封装factory方法 public static SqlSessionFactory getFactory(){ return factory; } //封装sqlSession会话 public static SqlSession getSqlSession(boolean isAutoCommit) throws IOException { SqlSession sqlSession=local.get(); if (sqlSession==null){ //通过SqLSessionFactory 调HjopenSession方法获取SqLSession对象时,可以通过参数设置事务是否自动提交 // 如果参数设置为true,表示自定提交事务:factory.openSession(true); //如果参数设置为false,或者不设置参数,表示手动提交:factory .openSession() ; /factory.openSession(false); sqlSession=factory.openSession(isAutoCommit); local.set(sqlSession); } return sqlSession ; } //封装getSession方法 手动提交用getSession public static SqlSession getSqlSession() throws IOException { return getSqlSession(false); } //使用泛型封装getMapper 自动提交用getMapper public static <T extends Object>T getMapper(Class<T> c) throws IOException { SqlSession sqlSession=getSqlSession(true); return sqlSession.getMapper(c); }
测试操作
@org.junit.Test //自动提交 public void testDeleteStudent() throws IOException { StudentDAO studentDAO=MybatisUtils.getMapper(StudentDAO.class); int i=studentDAO.deleteStudent("1001"); //提交事务方法 System.out.println(i); }
业务逻辑层自动事务管理
public class StudentServiceimpl implements StudentService { private StudentDAO studentDAO= MybatisUtils.getMapper(StudentDAO.class); public StudentServiceimpl() throws IOException { } @Override public boolean addStudent(Student student) { int i=studentDAO.insertStudent(student); boolean b=i>0; return b; } }
七.Mybatis主配置文件
mybatis-config.xml是Mybatis框架的主配置信息,只用于配置Mybatis数据源及属性信息
7.1properties标签
在resources目录下创建jdbc.properties文件用于键值对配置
mysql_driver=com.mysql.jdbc.Driver mysql_url=jdbc:mysql://localhost:3306/db_mybatis mysql_username=root mysql_password=123456
在mybatis-config.xml中通过properties标签引用jdbc.properties文件;引入之后,在配置environment时可以直接使用jdbc.properties的key获取对应的value
8.2setting标签
<!-- setting标签用于设置mybatis工作属性--> <settings> <!-- 启动二级缓存--> <setting name="cachEnable" value="true"/> <!-- 启动延迟加载--> <setting name="lazyLoadingEnable" value=""/> </settings>
8.3typeAliase标签 用于起别名
<!-- <typeAliases> 标签用于给实体类起别名 ,在映射文件中可以直接使用别名来替代实体类的全限定名- --> <typeAliases> <typeAlias type="com.hr.pojo.Student" alias="Student"/> </typeAliases>
8.4plugins标签
<!-- plugins用于配置mybatis插件例如(分页插件) --> <plugins> <plugin interceptor=""></plugin> </plugins>
8.5environments标签
<!-- 在environments配置奇偶数据库连接信息--> <!-- 在environments标签中可以配置多个encvieronments,每个encvieronments可以配置一套数据库连接信息 --> <!-- <! -- default属性,用来指定使用哪个environment标签–>--> <environments default="mysql"> <environment id="mysql"> <!-- transactionManager 用于配置数据库管理方式--> <!-- type="JDBC'以进行事务的提交和回滚操作--> <!-- type="MANAGED”依赖容器定成事务肾理,本身不进行事务的提交和回滚操作–>--> <transactionManager type="JDBC"></transactionManager> <!-- dataSource用于配置数据库连接信息 type="POOLED"/type="UNPOOLED"--> <dataSource type="POOLED"> <property name="driver" value="${mysql_driver}"/> <property name="url" value="${mysql_url}"/> <property name="username" value="${mysql_username}"/> <property name="password" value="${mysql_password}"/> </dataSource> </environment> </environments>
8.6mapper标签
加载映射配置 (映射文件,DAO注解)
<!--mapper用于载入映射文件 有多少个mapper载入多少 添加的映射文件--> <mappers> <mapper resource="mappers/StudentMapper.xml"></mapper> </mappers>
九.映射文件
9.1Mybatis的初始化
正在上传…重新上传取消
9.2Mapper跟标签
mapper文件相当于0AO接口的实现类',namespace属性要指定实现DAO接口的全限定名
9.3insert标签
声明添加操作(sql:insert.....)
常用属性
id属性:绑定DAO声明的方法名
parameterTpye属性,用以指定接口中对应的方法的参数的类型(可省略
useGeneratedKeys属性,设置添加操作是否需要回填生成的主键
kevPreperty属性,指定回填的id设置到参数对象中的哪个属性 timeout属性,设置此操作的超时时间,如果不设置则一直等待
主键回填
<!-- id对应方法名 parameterType对应定实体类的路径--> <!-- useGeneratedKeys设置添加操作是否需要回填生成的主键--> <!-- keyProperty设置回填的主键值赋值到参数对象的哪个属情 也就是主键自增 --> <insert id="insertStudent" parameterType="com.hr.pojo.Student" useGeneratedKeys="true" keyProperty="stuID" > insert into tb_students(stu_num,stu_name,stu_gender,stu_age) values (#{stuNum},#{stuName},#{stuGender},#{stuAge}) </insert>
<insert id="insertStudent" > <selectKey keyProperty="stuID" resultType="java.lang.Integer"> select last_insert_id() </selectKey>> insert into tb_students(stu_num,stu_name,stu_gender,stu_age) values (#{stuNum},#{stuName},#{stuGender},#{stuAge}) </insert>
9.4delete标签
声明操作
9.5upadte标签
声明修改操作
9.6select标签
声明查询操作
id属性,指定绑定方法的方法名
parameterType属性,设置参数类型 resultType属性,指定当前sql返回数据封装的对象类型(实体类)
resultMap属性,指定从数据表到实体类的字段和属性的对应关系
useCache属性查询此操作是否需要缓存
timeout ,设置超时时间
9.7resultMap标签
<!-- 查询方法的第二种方式 resultMap id="" id可以随便起名字 type对象实体类的路径--> <!-- resultMap标签用于定义实体类与数据映射表达映射关系(ORM)--> <resultMap id="studentMap" type="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>
9.8cache标签
设置当前DAO进行数据库操作时的缓存属性设置
<cache type="" size="" readOnly="false"/>
9.9sqlincould
十.分页插件
分页插件是一个独立于Mybatis框架之外的第三方插件
10.1添加分页插件的依赖
pageHelper
<!-- pagehelpe分页插件依赖 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.1.10</version> </dependency>
10.2配置插件
在mybatis的主配置文件 mybatis-config.xml中通过plugins标签进行配置
<!-- plugins用于配置mybatis插件例如(分页插件) --> <plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> </plugins>
10.3分对学生信息进行分页查询
StudentDAO studentDAO=MybatisUtils.getMapper(StudentDAO.class); PageHelper.startPage(1,3); List<Student> students=studentDAO.listStudent(); PageInfo<Student> pageInfo=new PageInfo<Student>(students); //pageInfo中就包含了数据及分页信息 List<Student> list=pageInfo.getList(); for (Student stu:list ) { System.out.println(stu); }
10.4带条件分页
测试方法
/ 带条件分页方法实现 @Test public void testListStudentByGender() throws IOException { StudentDAO studentDAO=MybatisUtils.getMapper(StudentDAO.class); PageHelper.startPage(1,1); List<Student> students=studentDAO.listStudentByGender("女"); PageInfo pageInfo=new PageInfo<Student>(students); List<Student> list=pageInfo.getList(); for (Student s:list ) { System.out.println(s); }
xml 配置执行语句
<select id="listStudentByGender" resultMap="studentMap"> select <include refid="studentset"/> from tb_students where stu_gender=#{stuGender} </select>
DAO定义的方法
//带条件分页方法 public List<Student> listStudentByGender(String gender);
十一.关联映射
11.1实体关系
实体――数据实体,实体关系指的就是数据与数据之间的关系例如:
用户和角色、房屋和楼栋、订单和商品
实体关系分为一下四种:
-
·实例:一对一关联:人和身份证、学生和学生证、用户基本信息和详情
用户信息(30个字段,用户数量也很多)
数据表关系:
-
主键关联(用户表主键和详情表主键相同时,表示是匹配的数据)
-
唯一外键关联
用户基本信息表(5个字段) 用户详情表(20+) 用户ID,帐号,密码,姓名,最后登录时间 详情ID, 手机 …… uid(外键,唯一)
1 zhangsan........ 1 130395358 2
2 list 3 154964988 3
3 wangwu 2 1649766495 1
用户登录:根据用户名查询用户信息,当用户表中数据量很大且字段很多时会严重影响查询的速度
一对多关联:多对一关联
实例
-
一对多 班级和学生 类别和商品
-
多对一 学生和班级 商品和类别
数据表关系:
-
在多的一端添加外键和一对一段进行关联
多对多关联
实例:用户和角色,角色和权限,房屋和业主,学生和社团订单和商品
数据表关系:建立第三张关系表添加两个外键分别与两张表的主键关联
用户(userid) 用户角色表(uid.id) 角色(role_id)
11.2创建项目,部署Mybatis框架
步骤略
创建web项目(Maven)
<!--添加web依赖--> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> </dependencies>
部署mybatis框架
-
添加依赖
<!-- 添加mybatis依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> </dependency> <!-- 添加mysql驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.27</version> </dependency>
配置文件
jdbc
mysql_driver=com.mysql.jdbc.Driver mysql_url=jdbc:mysql://localhost:3306/db_mybatis mysql_username=root mysql_password=123456
-
<?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> <!-- 用来引用jdbc文件--> <properties resource="jdbc.properties"> </properties> <environments default="mysql"> <environment id="mysql"> <!-- 事务管理 jdbc--> <transactionManager type="JDBC"></transactionManager> <!-- 数据库的连接池--> <dataSource type="POOLED"> <property name="driver" value="${mysql_driver}"/> <property name="url" value="${mysql_url}"/> <property name="username" value="${mysql_username}"/> <property name="password" value="${mysql_password}"/> </dataSource> </environment> </environments> </configuration>
帮助类
package com.hr.utils; 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 java.io.InputStream; public class MybatisUtils { private static SqlSessionFactory factory; private static final ThreadLocal<SqlSession> locol=new ThreadLocal<SqlSession>(); static { try { InputStream is= Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder(); factory=builder.build(is); }catch (Exception e){ e.printStackTrace(); } } public static SqlSessionFactory SqlSessionFactory() { return factory; } private static SqlSession getSqlSession(boolean isAutoCommit){ SqlSession sqlSession=locol.get(); if (sqlSession==null){ sqlSession=factory.openSession(isAutoCommit); locol.set(sqlSession); } return sqlSession; } //手动提交 public static SqlSession getSqlSession(){ return getSqlSession(false); } //自动提交 public static <T extends Object> T getMapper(Class<T> c){ SqlSession sqlSession= getSqlSession(true); return sqlSession.getMapper(c); } }
11.3一对一关联
用户-----和详情
11.3.1创建数据表
User
--用户信息表 create table users( user_id int primary key auto_increment, user_name varchar(20) not null uunique, user_pwd varchar(20) not null, user_realname varchar(20) not null, user_img varchar(100) not null );
Detail
-----用户详情表 create table details( detail_id int primary key auto_increment, user_addr varchar(50) not null, user_tel char(11) not null, user_desc varchar(200), uid int not null unique, --constraint FK_USER foreign key(uid) references users(user_id) );
添加unique表示唯一外键,只能连接一个表做外键
constraint FK_USER foreign key(uid) references users(user_id) 物理关联
11.3.3创建DAO中的方法
方法 |
---|
package com.hr.Dao;import com.hr.pojo.User;public interface UserDAO { public int insertUser(User user); public User queryUser(String username);} |
添加操作
添加查询操作 |
---|
package com.hr.Dao; import com.hr.pojo.Detail; import com.hr.pojo.User; import com.hr.utils.MybatisUtils; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import javax.xml.crypto.Data; import static org.junit.Assert.*; public class UserDAOTest { @Test public void testInsertUser(){ User user=new User(0,"gsgdg","123444","啊鬼打鬼","13.jpg",null); Detail detail=new Detail(0,"湖北武汉市","136556558","要发三个傻瓜",0); SqlSession sqlSession=MybatisUtils.getSqlSession(); try { //1 UserDAO userDAO= sqlSession.getMapper(UserDAO.class); int i=userDAO.insertUser(user); System.out.println(user); System.out.println(i); //2将user表 获取的回填userid给detail表 这样detail表也拥有了回填userid detail.setUserId( user.getUserId() ); //3 DetailDAO detailDAO=sqlSession.getMapper(DetailDAO.class); int j=detailDAO.InsertDetail(detail); System.out.println(detail); System.out.println(j); //手动提交事务 sqlSession.commit(); }catch (Exception e){ e.printStackTrace(); //是无回滚 防止一个运行失败 另一个运行成功 sqlSession.rollback(); } } @Test public void testQueryUser(){ UserDAO userDAO=MybatisUtils.getMapper(UserDAO.class); User user=userDAO.queryUser("zhangsan"); System.out.println(user); } }
11.3.4一对一关联查询
在查询用户的同时关联查询出与之对应的详情
-
实体
User | Detail |
---|---|
-
映射文件
1.第一种连接查询
<resultMap id="UserMap" type="User"> <id column="user_id" property="userId"/> <result column="user_name" property="userName"/> <result column="user_pwd" property="userPwd"/> <result column="user_realname" property="userRealname"/> <result column="user_img" property="userImg"/> <result column="detail_id" property="detail.detailId"/> <result column="user_addr" property="detail.userAddr"/> <result column="user_tel" property="detail.userTel"/> <result column="user_desc" property="detail.userDesc"/> </resultMap> <select id="queryUser" resultMap="UserMap"> select user_id,user_name,user_pwd,user_realname,user_img,detail_id,user_addr,user_tel,user_desc from users u inner join details d on u.user_id=d.uid where user_name=#{userNmae} </select>
2.第二种子查询
tebailMapper.xml字表查询
<resultMap id="com.hr.pojo.Detail" type="Detail"> <id column="detail_id" property="detailId"/> <result column="user_addr" property="userAddr"/> <result column="user_tel" property="userTel"/> <result column="user_desc" property="userDesc"/> </resultMap> <select id="QuertDetailByuid" resultMap="Detail"> select detail_id user_addr,user_tel,user_desc from details where uid=#{userId} </select>
<resultMap id="UserMap" type="User"> <id column="user_id" property="userId"/> <result column="user_name" property="userName"/> <result column="user_pwd" property="userPwd"/> <result column="user_realname" property="userRealname"/> <result column="user_img" property="userImg"/> <!-- association调用子查询 关联查询一个对象--> <association property="deatil" select="com.hr.Dao.DetailDAO.QuertDetailByuid" column="user_id"/> </resultMap> <select id="queryUser" resultMap="UserMap"> select user_id,user_name,user_pwd,user_realname,user_img from users where user_name=#{userNmae} </select>
UserMapper.xml查询
11.4一对多
案例:班级(1)对学生(n)
11.4.1
--创建班级信息表 create table classes( cid int primary key auto_increment, cname varchar(30) not null unique, cdesc varchar(100) ); --创建学生信息表 create table students( sid char(5) not null, sname varchar(20) not null, sage int not null, scid int null );
11.4.2创建实体类
班级 | 学生 |
---|---|
11.4.3关联查询
当查询一个班级的时候,要关联查询出这个班的所有学生
连接查询
<resultMap id="classMap" type="Clazz"> <id column="cid" property="classId"/> <result column="cname" property="className"/> <result column="cdesc" property="classDesc"/> <!-- Clazz对象的stus属性是一个list标签 需要使用collection标签--> <!-- collection标签中 ofType属性声明的是集合中元素的类型--> <collection property="stus" ofType="Student"> <result column="sid" property="stuId"/> <result column="sname" property="stuName"/> <result column="sage" property="stuAge"/> </collection> </resultMap> <select id="queryClass" resultMap="classMap"> select cid,cname,cdesc,sid,sname,sage FROM classes c INNER JOIN students s on c.cid=s.scid WHERE c.cid=1; </select>
子查询
咋查询的映射配置 |
---|
<?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.hr.Dao.StudentDAO"> <resultMap id="StudentMap" type="Student"> <id column="sid" property="stuId"/> <result column="sname" property="stuName"/> <result column="sage" property="stuAge"/> <result column="scid" property="stuCid"/> </resultMap> <select id="listStudentByid" resultMap="StudentMap"> select sid,sname,sage,scid from students where scid=#{cid} </select> </mapper>
<resultMap id="classMap" type="Clazz"> <id column="cid" property="classId"/> <result column="cname" property="className"/> <result column="cdesc" property="classDesc"/> <collection property="stus" select="com.hr.Dao.StudentDAO.listStudentByid" column="cid"/> </resultMap> <select id="queryClass" resultMap="classMap"> select cid,cname,cdesc FROM classes WHERE cid=#{classID}; </select>
studentDAO方法定义
ClassDAO方法定义
11.5一对多关联
实例 学生(n)对班级(1)
当查询这个学生的时候,关联查询这个学生所在的班级
-
连接查询
连接查询的映射配置 Student.xml |
---|
<!-- 多对一查询--> <!-- 方法一连接查询--> <resultMap id="studentMap" type="Student"> <id column="sid" property="stuId"/> <result column="sname" property="stuName"/> <result column="sage" property="stuAge"/> <result column="cid" property="clazz.classId"/> <result column="cname" property="clazz.className"/> <result column="cdesc" property="clazz.classDesc"/> </resultMap> <select id="queryStudentByid" resultMap="studentMap"> select sid,sname,sage,scid,cid,cname,cdesc from students s inner join classes c on s.scid=c.cid where s.sid=#{stuId} </select>
-
子查询
子查询映射配置 ClassMapper.xml 和StudentMapper.xml |
---|
11.6多对多连表查询
案例 学生(n)对课程(n)
11.6.1创建课程数据表
--学生信息表如上 --课程信息表 create table courses( course_id int primary key auto_increment, course_name varchar(50) not null ); --选课信息表/成绩表 create table grades( sid char(5) not null, cid int not null, score int not null )
11.6.2关联查询
查询学生时,同时查询学生学生选择的课程
Student | Course |
---|---|
根据课程编号查询课程时,同时查询了选择这门课程的学生信息
Student | Course |
---|---|
连接查询映射配置CourseMapper.xml |
---|
<resultMap id="courseMap" type="Course"> <id column="course_id" property="courseId"/> <result column="course_name" property="courseName"/> <collection property="students" ofType="Student"> <result column="sid" property="stuId"/> <result column="sname" property="stuName"/> <result column="sage" property="stuAge"/> </collection> </resultMap> <select id="queryCoursesByid" resultMap="courseMap"> select course_id,course_name,s.sid,sname,s.sage FROM courses c inner join grades g INNER JOIN students s on c.course_id=g.cid and g.sid=s.sid where c.course_id=1 </select>
-
在查询映射配置
StudentMapper.xml | CourseMapper.xml |
---|---|
StudentMapper.xml
<resultMap id="StudentMap2" type="Student"> <id column="sid" property="stuId"/> <result column="sname" property="stuName"/> <result column="sage" property="stuAge"/> </resultMap> <select id="queryStudentBycourseId" resultMap="StudentMap2"> select s.sid,sname,sage FROM students s INNER JOIN grades g on s.sid=g.sid where g.cid=1 </select>
CourseMapper.xml
<resultMap id="courseMap" type="Course"> <id column="course_id" property="courseId"/> <result column="course_name" property="courseName"/> <collection property="students" select="com.hr.Dao.StudentDAO.queryStudentBycourseId" column="course_id"/> </resultMap> <select id="queryCoursesByid" resultMap="courseMap"> select course_id,course_name FROM courses where course_id=#{courseId} </select>
十二、动态sql
12.1什么是动态sql
根据查询条件动态完成SQL的拼接
12.2动态SQL使用案例
案例:心仪对象搜索
12.2.1创建数据表
create table members( member_id int primary key auto_increment, member_nick varchar(20) not null unique, member_gender char(2) not null, member_age int not null, member_city varchar(30) not null );
12.2.2创建实体类
//@Data @NoArgsConstructor @AllArgsConstructor @ToString public class Memebr { private int memberId; private String memberNick; private String memberGender; private int memberAge; private String memberCity;
12.2.3创建DAO接口
在DAO接口中定义一个或者多个条件查询的方法
public interface MemberDAO{ //再多条件查询中,如果查询条件不确定,可以直接使用HashMap作为参数, //优点:无需单独定义传递查询条件的类 //缺点:当/向Map中存放参数时. key必须与动态sqL保持一致() // public List<Member> searchMember(HashMap<String,Object> params); //也可以定义专门用于存放查询条件的实体类存放参数 //优点:设置参数时 无需关注属性名 //缺点:需要单独定义一个类单独封装 public List<Member> searchMember(MemberSearchCondition params); }
在定义一个实体类存放参数
@NoArgsConstructor @AllArgsConstructor public class MemberSearchCondition { private String gender; private Integer minAge; private Integer maxAge; private String City;
动态创建 MemberMapper.xml的sql语句
12.2.4 if方法
<resultMap id="memberMap" type="Member"> <id column="member_id" property="memberId"/> <result column="member_nick" property="memberNick"/> <result column="member_gender" property="memberGender"/> <result column="member_age" property="memberAge"/> <result column="member_city" property="memberCity"/> </resultMap> <!--第一种方法 where 1=1 才能保证添加and 不报错 第二种是where标签 忽略了and--> <!-- <trim prefix="where" prefixOverrides="and | or" suffix="order by member_age"> 前缀prefix定义的是方法 prefixOverrides是定义的忽略and or suffix后缀 order by member_age 排序--> <select id="searchMember" resultMap="memberMap"> select member_id,member_nick,member_gender,member_age,member_city from members where 1=1 <if test="gender !=null"><!---gender就是参数对象的属性/参数Map的key--> and member_gender=#{gender} </if> <if test="minAge !=null"> and member_age >=#{minAge}<!--> 是>号的意思--> </if> <if test="maxAge !=null"> and member_age <=#{maxAge}<!--< 是<号的意思--> </if> <if test="City !=null"> and member_city=#{City}<!--< 是<号的意思--> </if> </select>
12.2.5<where>标签方法
<resultMap id="memberMap" type="Member"> <id column="member_id" property="memberId"/> <result column="member_nick" property="memberNick"/> <result column="member_gender" property="memberGender"/> <result column="member_age" property="memberAge"/> <result column="member_city" property="memberCity"/> </resultMap> <!--第一种方法 where 1=1 才能保证添加and 不报错 第二种是where标签 忽略了and--> <!-- <trim prefix="where" prefixOverrides="and | or" suffix="order by member_age"> 前缀prefix定义的是方法 prefixOverrides是定义的忽略and or suffix后缀 order by member_age 排序--> <select id="searchMember" resultMap="memberMap"> select member_id,member_nick,member_gender,member_age,member_city from members <where> <if test="gender !=null"><!---gender就是参数对象的属性/参数Map的key--> and member_gender=#{gender} </if> <if test="minAge !=null"> and member_age >=#{minAge}<!--> 是>号的意思--> </if> <if test="maxAge !=null"> and member_age <=#{maxAge}<!--< 是<号的意思--> </if> <if test="City !=null"> and member_city=#{City}<!--< 是<号的意思--> </if> </where> </select>
12.2.6<trim>方法
<mapper namespace="com.hr.Dao.MemberDAO"> <resultMap id="memberMap" type="Member"> <id column="member_id" property="memberId"/> <result column="member_nick" property="memberNick"/> <result column="member_gender" property="memberGender"/> <result column="member_age" property="memberAge"/> <result column="member_city" property="memberCity"/> </resultMap> <!--第一种方法 where 1=1 才能保证添加and 不报错 第二种是where标签 忽略了and--> <!-- <trim prefix="where" prefixOverrides="and | or" suffix="order by member_age"> 前缀prefix定义的是方法 prefixOverrides是定义的忽略and or suffix后缀 order by member_age 排序--> <select id="searchMember" resultMap="memberMap"> select member_id,member_nick,member_gender,member_age,member_city from members <trim prefix="where" prefixOverrides="and | or" suffix="order by member_age"> <if test="gender !=null"><!---gender就是参数对象的属性/参数Map的key--> and member_gender=#{gender} </if> <if test="minAge !=null"> and member_age >=#{minAge}<!--> 是>号的意思--> </if> <if test="maxAge !=null"> and member_age <=#{maxAge}<!--< 是<号的意思--> </if> <if test="City !=null"> and member_city=#{City}<!--< 是<号的意思--> </if> </trim> </select>
创建测试类测试
public class MemberDAOTest { @Test public void testSearchMember() { // HashMap<String,Object> params=new HashMap<String, Object>(); // params.put("gender","女"); // params.put("minAge",18); // params.put("maxAge",23); // params.put("city","武汉"); //------------------------------------------------------------- //可以任意根据一个参数 动态查询 MemberSearchCondition params2=new MemberSearchCondition(); params2.setGenDer("女"); // params2.setMinAge(18); // params2.setMaxAge(23); // params2.setCity("武汉"); //======================================》》》》》》》》》》》》》》》》》》》 MemberDAO memberDAO= MybatisUtils.getMapper(MemberDAO.class); List<Member> members=memberDAO.searchMember(params2);//参数可以换成params2 for (Member m:members) { System.out.println(m); } } }
12.2.7foreach方法
创建方法
//查询多个城市 public List<Member> searchMemberByCity(List<String> cities);
创建xml sql语句
<resultMap id="memberMap" type="Member"> <id column="member_id" property="memberId"/> <result column="member_nick" property="memberNick"/> <result column="member_gender" property="memberGender"/> <result column="member_age" property="memberAge"/> <result column="member_city" property="memberCity"/> </resultMap> <!-- foreach collection="list" item="cityName" separator="," open="(" close=")" collection="list" 定一个是定义存放容器的类型 item="cityName" 集合中每一个元素进行迭代时的别名, separator="," 因为要取到多个条件 所以要定义分隔符 open="(" close=")" 因为要取到(武汉,宜昌)这样的格式 所以要设置开头结尾 --> <select id="searchMemberByCity" resultMap="memberMap"> select member_id,member_nick,member_gender,member_age,member_city from members where member_city in <foreach collection="list" item="cityName" separator="," open="(" close=")"> #{cityName} </foreach> </select>
创建测试类
@Test public void searchMemberByCity() { List<String> cities=new ArrayList<String>(); cities.add("武汉"); cities.add("宜昌"); MemberDAO memberDAO= MybatisUtils.getMapper(MemberDAO.class); List<Member> members=memberDAO.searchMemberByCity(cities); for (Member m:members) { System.out.println(m); } }
十三.模糊查询
13.1.1创建DAO方法 方法一
public interface MemberDAO{ //根据昵称查询用户信息-模糊查询 public List<Member> searchMemberByNick(HashMap params); }
创建xml映射文件
<resultMap id="memberMap" type="Member"> <id column="member_id" property="memberId"/> <result column="member_nick" property="memberNick"/> <result column="member_gender" property="memberGender"/> <result column="member_age" property="memberAge"/> <result column="member_city" property="memberCity"/> </resultMap> <select id="searchMemberByNick" resultMap="memberMap"> select member_id,member_nick,member_gender,member_age,member_city from members where member_nick like '%${keyWord}%' </select> <!--${key}表示获取参数,先获取参数的值拼接到SQL语句中,再编译执行sql语句 可能引起SQL注入阿您 --> <!--#{key}表示获取参数,先完成SQL编译(预编译),预编译之后再将获取的参数设置到sql中 可以避免SQL注入问题 -->
测试方法
@Test public void testsearchMemberByNick(){ MemberDAO memberDAO=MybatisUtils.getMapper(MemberDAO.class); HashMap<String,Object> params=new HashMap<>(); params.put("keyWord","花"); List<Member> members=memberDAO.searchMemberByNick(params); for (Member b:members) { System.out.println(b); } }
方法二
不使用hashmap 用String参数
public interface MemberDAO{ //根据昵称查询用户信息-模糊查询 //模糊查询需要使用${科}取值,与sql进行拼接 //在使用${}时,即使只有一个参数也需要使用@Param注解声明参数的key(非String对象参数可以不用声明) public List<Member> searchMemberByNick(@Param("keyWord") String params); }
创建xml映射文件
<!--如果参数时String类型,需要parameterType声明参数类型--> <select id="searchMemberByNick" parameterType="java.lang.String" resultMap="memberMap"> select member_id,member_nick,member_gender,member_age,member_city from members where member_nick like '%${keyWord}%' </select> <!--${key}表示获取参数,先获取参数的值拼接到SQL语句中,再编译执行sql语句 可能引起SQL注入问题 --> <!--#{key}表示获取参数,先完成SQL编译(预编译),预编译之后再将获取的参数设置到sql中 可以避免SQL注入问题 -->
测试方法
@Test public void testsearchMemberByNick(){ MemberDAO memberDAO=MybatisUtils.getMapper(MemberDAO.class); List<Member> members=memberDAO.searchMemberByNick("花"); for (Member b:members) { System.out.println(b); } }
13.2#{}和${}的区别
<!--${key}表示获取参数,先获取参数的值拼接到SQL语句中,再编译执行sql语句 可能引起SQL注入问题 --> <!--#{key}表示获取参数,先完成SQL编译(预编译),预编译之后再将获取的参数设置到sql中 可以避免SQL注入问题 -->
十四、MyBatis日志配置
MyBatis做为一个封装好的ORM框架,其运行过程我们没办法跟踪,为了让开发者了解MBatis执行流程及每个执行步骤所完成的工作,MvBatis框架本身继承了log4i日志框架,对运行的过程进行跟踪记录。我们只需要对 MyBatis进行相关的日志配置,就可以看到MyBatis运行过程中的日志信息
14.添加日志框架依赖
<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
14.2添加日志配置文件
-
在resources目录下创建名为log4j.properties文件
-
在log4j.properties文件配置日志输出 的方式
#声明日志的输出级别及输出方式 log4j.rootLogger=DEBUG,stdout #MyBatis Logging configuration. . . log4j.logger.org.mybatis.example.BlogMapper=TRACE #Console output. . . log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout #定义日志的打印格式 %t表示线程名称 %5p 日志级别 %msg日志信息 loh4j.appender.stdout.layout.ConversionPattern=[%t] %5p - %msg \:%n%m
14.3日志信息的级别
十五.配置数据库连接池
MyBatis做为一个ORM框架,在进行数据库操作时是需要和数据库连接连接的,MxBatis支持基于数据库连接池的连接创建方式。
当我们配置MvBatis数据源时,只要配置了dataSaurce标签的type属性值为POOLED时,就可以使用MMBatis内置的连接池管理连接。
如果我们想要使用第三方的数据库连接池,则需进行自定义配置。
15.1常见的连接池
-
DBCP
-
C3PO
-
Druid 性能也比较好,提供了比较便捷的监控
-
Hikari 性能最好
15.2添加Durid依赖
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.5</version> </dependency>
15.3创建Druid连接池工厂
public class DruidDataSourceFactory extends PooledDataSourceFactory { public DruidDataSourceFactory(){ this.dataSource=new DruidDataSource(); } }
15.4将MyBatis的连接池替换为Druid
<environments default="mysql"> <environment id="mysql"> <!-- 事务管理 jdbc--> <transactionManager type="JDBC"></transactionManager> <!-- 数据库的连接池--> <!-- POOLED使用MyBatis内置的连接池实现--> <!-- mybatis需要一个连接池工厂,这个工厂可以产生数据库连接池PooledDataSourceFactory --> <dataSource type="com.hr.utils.DruidDataSourceFactory"> <property name="driverClass" value="${mysql_driver}"/> <property name="jdbcUrl" value="${mysql_url}"/> <property name="username" value="${mysql_username}"/> <property name="password" value="${mysql_password}"/> </dataSource> </environment> </environments>
十六、Mybatis缓存
MvBatis是基于JDBC的封装,使数据库操作更加便捷;MyBatis除了对JDBC操作步骤进行封装之外也对其性能进行了优化: 1·在MvBatis引入缓存机制,用于提升MyBatis的检索效率 2.在MvBatis引入延迟加载机制,用于减少对数据库不必要的访问
16.1一级缓存机制的原理
16.2Mybatis缓存
Mybatis缓存分为一级缓存和二级缓存
16.2.1一级缓存
一级缓存也叫做SqlSession级缓存,为每个SalSession单独分配的缓存内存,无需手动开启可直接使用;多个SalSession的缓存是不共享的。 特性: 1.如果多次查询使用的是同一个SalSession对象,则第一次查询之后数据会存放到缓存,后续的查询则直接访问缓存中存储的数据
2.如果第一次查询完成之后,对查询出的对象进行修改(此修改会影响到缓存),第二次查询会直接访问缓存,造成第二次查询的结果与数据库不一致; 3.当我们进行在查询时想要跳过缓存直接查询数据库,则可以通过sglSession.clearCache(;来清除当前SqlSession的缓存
4.如果第一次查询之后第二查询之前,使用当前的salsession执行了修改操作,此修改操作会使第一次查询并缓存的数据失效,因此第二次查询会再次访问数据库。
16.2.2两次查询不一致问题
16.2.3二级缓存
二级缓存 也称之为SqlSessionFactory级缓存,通过同一个factory对象获取的Sqlsession可以共享二级缓存
应用服务器中SqlSessionFactory是单例的,因此我们二级缓存可以实现全局共享
特性:
1.二级缓存默认没有开启,需要在mybatis-config.xml中的settings标签开启 2.二级缓存只能缓存实现序列化接的对象
-
在Mybatis-config.xml 开启二级缓存
<settings> <setting name="cachEnabled" value="true"/> </settings>
-
在需要使用二级缓存的Mapper文件中配置cache标签使用功能二级缓存
<cache/>
-
被缓存的实体类实现序列化接口
-
public class Member implements Serializable { private int memberId; private String memberNick; private String memberGender; private int memberAge; private String memberCity; }
测试
1.多个SqLSession对象必须来自同一个SqlSessionFactory
@Test public void testQueryMemberById(){ SqlSessionFactory factory =MybatisUtils.SqlSessionFactory(); // 1.多个SqLSession对象必须来自同一个SqlSessionFactory SqlSession sqlSession1=factory.openSession(true); SqlSession sqlSession2=factory.openSession(true); System.out.println(sqlSession1==sqlSession2); //返回为false 不是同一个 MemberDAO memberDAO1=sqlSession1.getMapper(MemberDAO.class); Member member1=memberDAO1.queryMemberById(1); System.out.println(member1); sqlSession1.commit();//第一次查询之后执行sqlSession1.commit(),会将当前salsession的查询结果缓存到二级缓存 System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); MemberDAO memberDAO2=sqlSession2.getMapper(MemberDAO.class); Member member2=memberDAO1.queryMemberById(1); System.out.println(member2); }
16.3查询操作的缓存开关
<!-- useCache="false 表示查询的时候是否使用缓存"--> <select id="queryMemberById" resultMap="memberMap" useCache="false"> select member_id,member_nick,member_gender,member_age,member_city from members where member_id=#{mid} </select>
十七.延迟加载(只在子查询中使用)
延迟加载─—如果在MxBatis开启了延迟加载,在执行了子查询(至少查询两次及以上)时,默认只执行第一次查询,当用到子查询的查询结果时,才会触发子查询的执行;如果无需使用子查询结果,则子查询不会执行。
16.1创建实体类
Clazz | Student |
---|---|
16.2创建DAO类方法
ClassDAO | StudentDAO |
---|---|
16.3创建子链接操做
ClassMapper.xml | StudentMapper.xml |
---|---|
16.4创建测试类 编写方法
package com.hr.Dao; import com.hr.pojo.Clazz; import com.hr.utils.MybatisUtils; import org.junit.Test; import static org.junit.Assert.*; public class ClassDAOTest { //延迟加载测试类 @Test public void queryClassById() { ClassDAO classDAO= MybatisUtils.getMapper(ClassDAO.class); Clazz clazz=classDAO.queryClassById(1); System.out.println(clazz.getClassName()); MybatisUtils.close();//当地一次查询之后关闭SqlSession 下面查询会自动重新执行 System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ "); System.out.println(clazz.getStus()); } }