MyBatis框架常用优化方法

一、优化之Session工具类

1、单独使用 MyBatis时,可以封装一个用来获取MyBatis中Session的工具类

回顾之前使用Mybatis来操作数据库的步骤:
(1)启动mybatis框架( SqlSession---->SqlSessionFactory---->SqlSessionFactoryBuilder)
(2)通过 SqlSessionFactoryBuilder来得到SqlSessionFactory ;
(3)通过SqlSessionFactory 来创建SqlSession;
(4)读source文件下的mybatis.xml,将mybatis.xml文件转化成流
(5)创建SqlSession对象

public static SqlSession session;

   //启动mybatis框架,读配置文件,获取Session对象
   public void getSession() throws IOException{
        // (1)启动mybatis框架
        // SqlSession---->SqlSessionFactory---->SqlSessionFactoryBuilder
        SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
        // 读source文件下的mybatis.xml,将mybatis.xml文件转化成流
        InputStream ins = Resources.getResourceAsStream("mybatis.xml");
        // (2)创建SQLSessionFactory工厂对象
        SqlSessionFactory ssf = sfb.build(ins);
        // (3)创建SqlSession对象
         session = ssf.openSession();
    }

每次操作数据库都要重复上述步骤,因此,可以像封装jdbcUtil一样,将它封装成一个工具类!

2、MybatisUtil.java

package cn.java.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.IOException;
import java.io.InputStream;

public class MybatisUtil {
   //1.SqlSessionFactoryBuilder:
    // 作用:负责构建SqlSessionFactory对象,使用build()方法可创建多个SqlSessionFactory对象
    // 生命周期:只存在于方法体内,用过就不需要了
    // 一旦创建了SqlSessionFactory,就不再需要该类了,一般用于局部变量
   //2.SqlSessionFactory:MyBatis应用的核心
      //作用:创建SqlSession对象
      //生命周期:与应用的生命周期相同,作用于Application
    //  单例模式:factory的实例化的过程是一个比较耗费性能的过程
     // 一旦被创建就应该在应用的运行期间一直存在,保证有且只有一个factory,不要重新创建另一个,常使用单例模式
   //3.SqlSession:用于请求或方法的作用域,用完之后需要关闭,不要占用资源
     //作用:包含了执行SQL语句的所有方法
    //对应一次数据库会话,会话结束必须关闭

    private static SqlSessionFactory factory;

    //静态代码块,随着类的加载而执行,而且只执行一次
    static{
        try {
            InputStream is = Resources.getResourceAsStream("mybatis.xml");
            factory = new SqlSessionFactoryBuilder().build(is);
           // threadLocal = new ThreadLocal<SqlSession>();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static SqlSession getSession(){
        SqlSession session=null;
        //通过session工厂获取到一个session
        session = factory.openSession();
        //调用session的查询集合方法
        return session;
    }


   //  关闭SqlSession
   public static void closeSession(SqlSession sqlSession){
       sqlSession.close();
   }

   //测试
   public static void main(String[] args) {
       //System.out.println(MybatisUtil.factory==MybatisUtil.factory);
       for (int i = 0; i < 5; i++) {
           System.out.println(MybatisUtil.factory.hashCode());
       }
   }
}

以后每次使用只需要调用即可,不用重复编写加载配置文件和创建SqlSession代码,数据库操作完成后,SqlSession关闭。

二、优化之将连接字符串写入配置文件

引入数据库配置文件

<!-- 引入数据库配置文件 -->
	<properties resource="database.properties"/>

	<settings>
		<setting name="logImpl" value="LOG4j"/>
	</settings>

	<!-- 配置数据库连接环境:driver、url、username、password -->
	<environments default="mysql">
		<!-- 开始配置mysql -->
		<environment id="mysql">
			<!--配置事务  -->
			<transactionManager type="JDBC"></transactionManager>
			<!-- 配置数据源 -->
			<dataSource type="POOLED">
				<property name="driver" value="${driver}"/>
				<property name="url" value="${url}"/>
				<property name="username" value="${username}"/>
				<property name="password" value="${password}"/>
			</dataSource>
	   </environment>

	</environments>

三、优化之去DAO层

目的是简化项目结构
请添加图片描述
Mybatis局部配置文件名一定要与它所支持的mapper层中的接口同名,如:UserMapper.xml要与UserMapper.java同名。可以将mapper层接口与Mybatis局部配置文件放在同一个包下,mapper层接口中定义的方法名,一定要与Mybatis局部配置文件的SQL语句的id同名,注意mapper层中,没有接口的实现类。

四、优化之使用@Before、@After注解

1、@Before注解

在测试类中的某个方法前加@Before注解,可以使得在执行其他方法,先执行该方法。

 //Before注解:在每次调用测试方法之前,自动调用init()方法
    @Before
    public void init(){
        session= MybatisUtil.getSession();
        //um就是Mapper的实现类
        um=session.getMapper(UserMapper.class);
    }

2、@After注解

在测试类中的某个方法前加@After注解,可以使得在执行其他方法,再执行该方法。

 //每次调用测试方法之后,自动调用一下destory()
    @After
    public void destory(){
        MybatisUtil.closeSession(session);
    }

五、优化之使用@Select注解

六、优化之使用别名

给包下所有的实体类取别名

<!-- 配置别名 -->
	<typeAliases>
		<typeAlias type="cn.java.pojo.Student" alias="student"/>
		<typeAlias type="cn.java.pojo.User" alias="user"/>
	</typeAliases>

七、MyBatis 框架的优化练习

1、数据库准备

在MySchool数据库中,建立一个student表,表结构如下:

student(
id bigint(20) 自增,
sname varchar(40),
dept varchar(40),
age int)

并在表中插入几条数据,其中一条为自己的信息

2、完整代码

database.properties
#mysql8
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql:///myschool?serverTimezone=Hongkong
username=root
password=你的密码
log4j.properties
log4j.rootLogger=DEBUG, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender  
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout  
log4j.appender.CONSOLE.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n 
mybatis.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>

	<!-- 引入数据库配置文件 -->
	<properties resource="database.properties"/>

	<!-- 开启log4j,输出SQL语句 -->
	<settings>
		<setting name="logImpl" value="LOG4j"/>
	</settings>

	<!-- 配置别名 -->
	<typeAliases>
		<typeAlias type="cn.java.pojo.Student" alias="student"/>
		<typeAlias type="cn.java.pojo.User" alias="user"/>
	</typeAliases>

	<!-- 配置数据库连接环境:driver、url、username、password -->
	<environments default="mysql">
		<!-- 开始配置mysql -->
		<environment id="mysql">
			<!--配置事务  -->
			<transactionManager type="JDBC"></transactionManager>
			<!-- 配置数据源 -->
			<dataSource type="POOLED">
				<property name="driver" value="${driver}"/>
				<property name="url" value="${url}"/>
				<property name="username" value="${username}"/>
				<property name="password" value="${password}"/>
			</dataSource>
	   </environment>

	</environments>
	
	<!-- 关联局部SQL映射配置文件 ,在每一个mapper里,指定SQL映射文件名及全路径,可使用“copy qualified name””-->
	<mappers>
		<package name="cn.java.mapper"/>
	</mappers>
	
	
</configuration>
Student.java
package cn.java.pojo;

public class Student {
    private Long id;
    private String sname;
    private String dept;
    private int age;

    public Student() {
    }

    public Student(Long id, String sname, String dept, int age) {
        this.id = id;
        this.sname = sname;
        this.dept = dept;
        this.age = age;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }

    public String getDept() {
        return dept;
    }

    public void setDept(String dept) {
        this.dept = dept;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student[" + "id=" + id + ", " +
                "sname='" + sname + '\'' +
                ", dept='" + dept + '\'' +
                ", age=" + age +
                ']';
    }
}
StudentMapper.java
package cn.java.mapper;

import cn.java.pojo.Student;
import org.apache.ibatis.annotations.Select;

import java.util.List;
import java.util.Map;

public interface StudentMapper {
    // 该方法使用Student实体类
    public List<Student> getAllStudent();

    //直接在以下方法上加@Select注解,简化代码
    @Select("select * from student")
    public List<Student> findAllStudent();

    // 该方法返回多条记录,不使用实体类,用Map数据类型去接受
    public List<Map<String, Object>>  getAllStudentMap();

    // 该方法使用了带一个参数的查询语句,返回一条记录
    public Map<String, Object> getStudentById(long id);

    // 该方法使用了有多个参数的 select语句
    public Map<String, Object> getStudentByMulCondition(Map<String, Object> map);

    // 该方法插入一条记录,带参数,更新操作一定要提交事务
    public int  addStudent(Map<String, Object> map);

    // 该方法插入多条记录,带参数,更新操作一定要提交事务
    public int addStudentBatch(List<Student> list) ;

    // 该方法使用了动态查询,查询条件不确定
    public List<Map<String, Object>>  getStudentByDynam(Map<String, Object> map) ;

    // 该方法使用了动态修改,查询条件不确定
    public int updateStudentByDynam(Map<String, Object> map)  ;

    //    根据id删除记录
    public long deleteStudentById(long id);
    //    根据多个id删除多条记录
    public int deleteStudentByIds(long[] ids);

}
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文件中的接口名一致-->
<!--  sql语句保存在Mybatis的局部配置文件中
     解释:
	(1)namespace:命名空间,其值为某一个dao层接口的具体路径,
	    表示这个类要使用相应的SQL语句,这个具体路径不要自己写,可以选中该类,右键,选择“copy reference”,然后粘贴即可
	(2)select标签存放查询语句;
	 (3)id:在整个配置文件中id值必须唯一,一般情况下,其值与dao层类中的使用该SQL语句的方法名保持一致;
	 (4)resultType:指定当前sql查询语句返回的数据类型。类型不是sql语句的最终类型,
	     而是某一条数据的类型,一般用实体类表示,也要用该实体类的“全路径”来表示,运行时系统会自动将实体类的对象创建出来
       (5)可以编写多条sql语句
 -->
<mapper namespace="cn.java.mapper.StudentMapper">
     <!-- 
		1.select语句返回多条User实体对象
		resultType="cn.java.entity.User"表示返回User实体类
	 -->
    <select id="getAllStudent" resultType="student">
		SELECT * FROM student
	</select>
	<!-- 
		2.select语句返回List<Map<String,Object>,可以不使用实体类,直接用Map数据类型,更加简单,简化程序
	 -->
	<select id="getAllStudentMap" resultType="Map">
		SELECT * FROM student
	</select>
	
	<!-- 
		3.SQL语句带一个参数
		parameterType:指定SQL语句接收的参数类型
	 -->
	<select id="getStudentById" resultType="map" parameterType="Long">
		SELECT * FROM student WHERE id=#{0}
	</select>
	
	<!--
		4.SQL语句带多个参数,用Map封装,parameterType=Map,返回一条记录,按key取参数值
		#在获取参数时可防止SQL注入攻击,应尽量使用#;模糊查询时,使用$
	  -->
	<select id="getStudentByMulCondition" resultType="map" parameterType="Map">
		SELECT * FROM student WHERE sname='${sname}' AND dept='${dept}' AND age='${age}'
	</select>
	
	<!-- 添加数据
		5. delete、insert、update操作没有resultType属性,默认返回int型
		  parameterType=Map,表示参数类型为Map,用Map封装参数
		  #表示在获取参数时可防止SQL注入攻击,应尽量使用#;模糊查询时,使用$
	      INSERT INTO users SET username=,这种SQL语句是MmySql特有的扩展功能
	 -->
	<insert id="addStudent" parameterType="Map">
		INSERT INTO student SET sname=#{sname},dept=#{dept},age=#{age}
	</insert>

	<insert id="addStudentBatch" parameterType="student">
		insert into
		student(sname,dept,age)
		values
		<foreach collection="list" item="student" separator=",">
			(#{student.sname},#{student.dept},#{student.age})
		</foreach>
	</insert>
	
	<!-- 
		6.动态SQL语句,实现动态查询
		  &lt:小于
		  &gt:大于
		  where标签:当有查询条件时,就使用where命令,当没有查询条件时,就不用where命令
		  if test:判断是否对某个字段进行查询
	 -->
	<select id="getStudentByDynam" resultType="Map" parameterType="Map">
		SELECT * FROM student
		<where>
			<if test="sname!=null">
				sname=#{sname}
			</if>
			<if test="dept!=null">
				and dept=#{dept}
			</if>
			<if test="age!=null">
				and age=#{age}
			</if>
		</where>
	</select>
	
	<!-- 
		7.动态修改update语句
		 set标签:当有更新字段时,就使用set命令,当没有更新字段时,
		     语句为UPDATE course SET id=NULL WHERE id=NULL
	 -->
	<update id="updateStudentByDynam" parameterType="Map">
	   update student
	   <set>
		   <if test="sname!=null">
			   sname=#{sname},
		   </if>
		   <if test="dept!=null">
			   dept=#{dept},
		   </if>
		   <if test="age!=null">
			   age=#{age},
		   </if>
		   id=#{id}
	   </set>
	   where id=#{id}
	</update>

	<!-- 
	    8.根据id删除记录
	    根据id删除学生记录
	-->
	<delete id="deleteStudentById" parameterType="long">
		DELETE FROM student WHERE id=#{id}
	</delete>

	<!-- 
	    9.根据多个id删除记录
	    根据多个id删除多个学生记录
	-->
	<delete id="deleteStudentByIds" parameterType="long[]" >
		DELETE FROM student WHERE id IN
		<foreach collection="array" item="id" open="(" close=")" separator=",">
			#{id}
		</foreach>
	</delete>
	
</mapper>


MybatisUtil.java
package cn.java.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.IOException;
import java.io.InputStream;

public class MybatisUtil {
   // 获取SqlSession
    public static SqlSession getSession(){
        SqlSession session=null;
        InputStream inputStream=null;
        try {
            //配置文件的路径
            String resource = "mybatis.xml";
            //加载配置文件,得到一个输入流
            inputStream = Resources.getResourceAsStream(resource);
            //获取MyBatis的Session工厂
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            //通过session工厂获取到一个session
            session = sqlSessionFactory.openSession(true);  //true表示自动提交事务
            //调用session的查询集合方法
            return session;
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

   //  关闭SqlSession
    public static void closeSession(SqlSession session){
        if(session!=null){
            session.close();
        }
    }
}

Test_Student.java
import cn.java.mapper.StudentMapper;
import cn.java.pojo.Student;
import cn.java.utils.MybatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Test_Student {
    // SqlSession session=null;
    SqlSession session=null;
    StudentMapper um=null;

    //Before注解:在每次调用测试方法之前,自动调用init()方法
    @Before
    public void init(){
        session= MybatisUtil.getSession();
        //um就是Mapper的实现类
        um=session.getMapper(StudentMapper.class);
    }
    //每次调用测试方法之后,自动调用一下destory()
    @After
    public void destory(){
        MybatisUtil.closeSession(session);
    }

    @Test
    public void testGetAllStudent(){
        um= session.getMapper(StudentMapper.class);
        List<Student> studentList = um.getAllStudent();
        for (Student student : studentList) {
            System.out.println(student);
        }
    }

    @Test
    public void testFindAllStudent(){

        List<Student> studentList = um.findAllStudent();
        for (Student student : studentList) {
            System.out.println(student);
        }
    }

    @Test
    // 2.该方法返回多条记录,不使用实体类,用Map数据类型去接受
    public void testGetAllStudentMap() {
        List<Map<String, Object>> studentList =um.getAllStudentMap();
        for (Map<String, Object> map : studentList) {
            System.out.println(map);
        }
    }

    @Test
    // 3.该方法使用了带一个参数的查询语句,返回一条记录
    public void testGetStudentById() {
        // 传递参数,直接传
        Long id =20201002222L;
        Map<String, Object> studentMap = um.getStudentById(id);
        System.out.println(studentMap);
    }

    @Test
    // 4.该方法使用了有多个参数的 select语句
    public void testGetStudentByMulCondition()  {
        // 声明一个Map对象,可以使用Map或实体类同时传递多个参数,用map更简单
        Map<String, Object> paramMap = new HashMap<String, Object>();
        // 封装参数
        paramMap.put("sname", "李四");
        paramMap.put("dept", "软件工程");
        paramMap.put("age", "21");
        // 传递参数
        Map<String, Object> studentMap = um.getStudentByMulCondition(paramMap);
        System.out.println(studentMap);
    }

    // 5.该方法插入一条记录,带参数,更新操作一定要提交事务
    @Test
    public void testAddStudent() {
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put("sname", "徐三");
        paramMap.put("dept", "计算机");
        paramMap.put("age", "19");
        int resultInt = um.addStudent(paramMap);
        System.out.println(resultInt);
    }

    // 6.该方法插入多条记录,带参数,更新操作一定要提交事务
    @Test
    public  void testAddStudentBatch() {
        List<Student> list = new ArrayList<>();
        Student student;
        for (int i = 0; i < 5; i++) {
            student = new Student();
            student.setSname("test" + i);
            student.setDept("网络安全");
            student.setAge(19);
            list.add(student);
        }
        int resultInt = um.addStudentBatch(list);
        System.out.println(resultInt);
    };

    // 7.该方法使用了动态查询,查询条件不确定
    @Test
    public void getStudentByDynam()  {
        // 可以使用Map或实体类同时传递多个参数
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put("age", "20");
        List<Map<String, Object>> studentList =um.getStudentByDynam(paramMap);
        for (Map<String, Object> map : studentList) {
            System.out.println(map);
        }
    }

    // 8.该方法使用了动态修改,查询条件不确定
    @Test
    public void updateStudentByDynam() {
        // 可以使用Map或实体类同时传递多个参数
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put("id","20201001111");
        paramMap.put("dept", "计算机");
        int resultInt = um.updateStudentByDynam(paramMap);
        System.out.println(resultInt);
    }

    @Test
    public void deleteStudentById(){
        long id = 20201005582L;
        long resInt = um.deleteStudentById(id);
        System.out.println(resInt);
    }

    @Test
    public void deleteStudentByIds(){
        long[] ids = new long[]{20201005574L,20201005575L,20201005576L,
                20201005577L,20201005578L,20201005579L,20201005581L};
        long resInt = um.deleteStudentByIds(ids);
        System.out.println(resInt);
    }



}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值