MyBatis基础篇

MyBatis基础篇

简介

注意:本篇文章主讲语法,jar包导入大家可以在网上搜索(有问题一定要学会利用搜索引擎解决!!!),全程代码会写到文章中。

     1.  MyBatis是一个半自动ORM框架(作为解决数据库发展和面向对象发展不一致的问题)

​ O:objict—面向对象

​ R:relation—关系型数据库

​ M:map—映射

​ 半自动:mybatis框架需要我们手写sql语句

​ mybatis框架不依赖于服务器

  1. 优点:

    (1):解决了SQL语句和Java代码之间的耦合

    (2):连接数据库速率比较快

    (3):取值问题会变得非常简单

数据准备


1.Flower类
mysql> select * from flower;
+----+-----------+-----------+------------+
| id | name      | price     | production |
+----+-----------+-----------+------------+
|  1 | 玫瑰花    |        15 | 中国       |
|  2 | 夕颜      |        18 | 中国       |
|  5 | 满天星    |      1314 | 挪威       |
|  6 | 牡丹      |         5 | 中国       |
|  7 | 丁香      |       188 | 锦州       |
|  8 | 杜鹃      |      1688 | 金陵       |
|  9 | 琉璃      |     18888 | 临安       |
| 10 | 彼岸花    | 188888888 | 黄泉       |
| 11 | 玫瑰花    |        15 | 咸阳       |
+----+-----------+-----------+------------+
9 rows in set (0.00 sec)

2.Student类
mysql> select * from student;
+-----+--------+---------+
| sid | sname  | clazzno |
+-----+--------+---------+
|   1 | 张三   |       1 |
|   2 | 李四   |       1 |
|   3 | 王五   |       2 |
|   4 | 赵六   |       3 |
|   5 | 田七   |       4 |
+-----+--------+---------+
5 rows in set (0.00 sec)

3.Clazz类
mysql> select * from clazz;
+---------+-----------------+
| clazzno | cname           |
+---------+-----------------+
|       1 | 505java班       |
|       2 | 509java班       |
|       3 | 402AI班级       |
|       4 | 203前端班级     |
+---------+-----------------+
4 rows in set (0.00 sec)

第一部分(基础)

框架代码


1.创建实体类(Flowerpackage pers.szs.entity;

public class Flower {

    private Integer id;
    private String name;
    private Integer price;
    private String production;

    public Flower() {
    }

    public Flower(Integer id, String name, Integer price, String production) {
        this.id = id;
        this.name = name;
        this.price = price;
        this.production = production;
    }

    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 Integer getPrice() {
        return price;
    }

    public void setPrice(Integer price) {
        this.price = price;
    }

    public String getProduction() {
        return production;
    }

    public void setProduction(String production) {
        this.production = production;
    }

    @Override
    public String toString() {
        return "Flower{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                ", production='" + production + '\'' +
                '}';
    }
}

        
  

        
2.配置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="jdbc.properties"></properties>  <!--配置属性:属性文件详见下方-->

    <!--设置-->
    <settings>  
        <setting name="logImpl" value="LOG4J"></setting>  <!--设置日志:文件详见下方-->
    </settings>

    <!--起别名-->
    <typeAliases>

        <package name="pers.szs.entity"></package>
        
    </typeAliases>


    <!--主要环境构建-->
    <environments default="mysql">  <!--默认环境-->

        <environment id="mysql">   <!--具体环境-->

            <transactionManager type="JDBC"></transactionManager>  <!--事务管理器-->

            <dataSource type="POOlED">  <!--数据源-->

                <property name="driver" value="${m_driver}"/>
                <property name="url" value="${m_url}"/>
                <property name="username" value="${m_user}"/>
                <property name="password" value="${m_password}"/>

            </dataSource>

        </environment>

    </environments>


    <!--
       mapper文件扫描
       一定要配置,不然扫描不到mapper文件
    -->
    <mappers>
        
        <package name="pers.szs.mapper"></package>

    </mappers>


</configuration>


属性文件(jdbc.properties):
    
m_driver=com.mysql.cj.jdbc.Driver
m_url=jdbc:mysql://localhost:3306/mybatis2?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
m_user=root
m_password=******
    
 日志文件(log4j.properties):
 log4j.rootCategory=error,console,logfile

log4j.logger.pers.szs.mapper=debug

log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=- %m%n

log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=d:/bjsxt.log
log4j.appender.logfile.Append=true
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%-4r [%t] %-5p %c %x -%m%n

 
    
注:
    日志记录等级:
    FATAL>ERROR>WAR>INFO>DEBUG 
   
 

接口(FlowerMapper)

package pers.szs.mapper;

import pers.szs.entity.Flower;

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

public interface FlowerMapper {

    //1.查询所有信息
    List<Flower> selectAll();


    //2.按照参数查询

    List<Flower> selectMore1(int id);
    List<Flower> selectMore2(String name,String production);
    List<Flower> selectMore3(Flower flower);
    List<Flower> selectMore4(Map<String,Object> map);
    
    //3.添加操作

    int insert1(int id,String name,int price,String producton);

    int insert2(Flower flower);
    
     //4.修改操作

    int update(int id,String name,int price,String producton);

    //5.删除操作
    int delete(int id);

    
}

FlowerMapper.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">



<!--命名空间:namespace 理论上名字可以随意起
           建议使用mapper接口和mapper文件所在的包的引用+mapper接口名来命名,此时mybatis会自动扫描mapper接口,并自动查找和接口同名的mapperxml文件
-->
<mapper namespace="pers.szs.mapper.FlowerMapper">



    <sql id="sql1">

        id,name,price,production

    </sql>

    <!--
          id:方法名
          resultType:返回值类型
          如果返回值是对象则返回对象的引用,如果返回值是集合,则返回泛型的引用(注意:此处已经在mybatis.xml中起别名(typeAliases),所以只需要写实体类类名,一般小写)
    -->
    <select id="selectAll" resultType="flower">

        select <include refid="sql1"></include> from flower

    </select>

    <select id="selectMore1" resultType="flower">

        select * from flower where id=#{param1}

    </select>


    <select id="selectMore2" resultType="flower">

        select * from flower where name=#{param1} and production=#{param2}

    </select>


    <select id="selectMore3" resultType="flower">

        <!--如果传入的参数是对象,可以直接在{}中写对象属性名-->
        select * from flower where name=#{name} and production=#{production}

    </select>

    <select id="selectMore4" resultType="flower">

        <!--如果传入的参数是Map集合,可以直接在{}中写key-->
        select * from flower where name=#{key1} and production=#{key2}

    </select>

    <!--update,delete,insert操作返回值均为整数,返回值类型可以不写-->


    <insert id="insert1">


        <!--flowerMapper.insert1(0, "山茶花", 1566, "四川");-->
        insert into flower values(default,#{param2},#{param3},#{param4})

    </insert>

    <insert id="insert2">

        insert into flower values(#{id},#{name},#{price},#{production})

    </insert>

    <update id="update">

        update flower set name=#{param2},price=#{param3},production=#{param4} where id=#{param1}

    </update>


    <delete id="delete">

        delete from flower where id=#{param1}

    </delete>


</mapper>


测试类(TestA)

package pers.szs.test;

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 pers.szs.entity.Flower;
import pers.szs.mapper.FlowerMapper;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TestA {
    public static void main(String[] args) throws IOException {

        //解析mybatis.xml文件
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");


        //创建sqlSession工厂

        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        //创建sqlSession对象

          //openSession(bool b) b默认为false:事务不会自动提交(即update,delete,insert操作不会自动提交至数据库,会保存到内存中,需要手动提交)
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        //调用方法

        FlowerMapper flowerMapper = sqlSession.getMapper(FlowerMapper.class);


        //关闭资源

        sqlSession.close();

    }
}

​ 通过第一部分的学习,我们已经掌握了利用mybatis实现基本的增删改查操作,但是我们可能会疑惑,利用mybatis进行操作似乎与直接在命令行或者图形界面操作没有区别,额,而且好像更加复杂了,因为需要我们配置许多文件,而且测试类需要使用许多我们不了解的类和接口。接下来我们就一起来看一看mybatis的强大之处。

第二部分(动态SQL)

1.九个标签:where if when set trim foreach band sql include(加粗的重点掌握,其他的用的不多,了解一下)

FlowerMapper2

package pers.szs.mapper;

import pers.szs.entity.Flower;

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

public interface FlowerMapper2 {

    //1.查询操作

    //if
    List<Flower> selectMore1(String name,String production);


    //choose when otherwise
    List<Flower> selectMore2(String name,String production);


    //foreach
    List<Flower> selectMore3(List<Integer> list);

    //bind(模糊查询)
    List<Flower> selectMore4(String name,String production);

    List<Flower> selectMore5(String name,String production);


    //2.修改操作

    int update1(Flower flower);


    int update2(Flower flower);




FlowerMapper2.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="pers.szs.mapper.FlowerMapper2">

    <!--动态SQL-->

    <select id="selectMore1" resultType="flower">

        select * from flower


        <!-- where if
        <where>:自动添加"where"关键字,并自动把多余的第一个and去掉
        -->
        <where>

            <if test="param1!=null and param1!=''">

                name=#{param1}

            </if>

            <if test="param2!=null and param2!=''">
                and production=#{param2}

            </if>


        </where>


    </select>

    <!--  where choose when otherwise-->
    <select id="selectMore2" resultType="flower">
        
        select * from flower
        
        <where>
            
            <choose>   <!--类似于switch()-->
                
                <when test="param1!=null and param1!=''">

                    name=#{param1}
                    
                </when>
                
                <when test="param2!=null and param2!=''">

                    and production=#{param2}

                </when>

                <otherwise>
                    1=1
                </otherwise>
                
            </choose>
            
            
        </where>

    <!--foreach-->
    </select>
    
    <select id="selectMore3" resultType="flower">
        
        
        select * from flower where id in

        <foreach collection="list" open="(" separator="," close=")" item="item">

            #{item}

        </foreach>

        
    </select>


    <select id="selectMore4" resultType="flower">

        select * from flower

        <where>

            <if test="param1!=null and param1!=''">

                name like '%${param1}%'

            </if>

            <if test="param2!=null and param2!=''">

                and production like '%${param2}%'

            </if>

        </where>

    </select>
    
    <select id="selectMore5" resultType="flower">
        
        select * from flower 
        
        <where>

            <if test="param1!=null and param1!=''">
                
                <bind name="pa1" value="'%'+param1+'%'"/>

                name like #{pa1}
            </if>


            <if test="param2!=null and param2!=''">

                <bind name="pa2" value="'%'+param2+'%'"/>

                production like #{pa2}

            </if>
            
        </where>
        
    </select>
    
    
    
    <!--set-->
    
    <update id="update1">

        update flower

        <!--
           set:自动添加"set"关键字,自动去除最后面多余的逗号;
        -->
        <set>

           <if test="name!=null and name!=''">

               name=#{name},

           </if>

            <if test="price>0">

                price=#{price},
            </if>

            <if test="production!=null and production!=''">

                production=#{production}

            </if>

        </set>

        where id=#{id}

    </update>


    <update id="update2">

        update flower

        <trim prefix="set" suffixOverrides=",">

            <if test="name!=null and name!=''">

                name=#{name},

            </if>

            <if test="price>0">

                price=#{price},
            </if>

            <if test="production!=null and production!=''">

                production=#{production}

            </if>


        </trim>

        where id=#{id}


    </update>


</mapper>

疑难点:第一个update操作 name like ‘%${name}%’ 为什么不能直接写 name like ‘%#{name}%’,反而却要利用bind标签

因为"#“底层为占位符’?’,” " 底 层 为 直 接 拼 写 , 而 此 处 不 支 持 占 位 符 , 所 以 只 能 用 ′ "底层为直接拼写,而此处不支持占位符,所以只能用' "'或者利用bind标签解决

其实学到这里大家对于mybatis应该都有了自己的理解,我个人认为mybatis关键在于一个字"拼";

好了,闲话少说,接下来继续学习多表查询

第三部分(多表查询)

三种方式:业务代码的方式

​ N+1

​ 多表查询SQL

StudentMapper(Intreface)

package pers.szs.mapper;

import pers.szs.entity.Clazz;
import pers.szs.entity.Student;

import java.util.List;

public interface StudentMapper {

    //查询所有学生的信息
    List<Student> selectAll();


    List<Student> selectAll2();

    List<Student> selectAll3();

    //按照班级编号查询班级信息
    Clazz selectOne(int clazzno);


    //根据班级编号查询学生信息
    List<Student> selectMore(int clazzno);
}

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 namespace="pers.szs.mapper.StudentMapper">

    <select id="selectMore" resultType="student">

        select * from student where clazzno=#{param1}
    </select>

    <!--业务代理方式-->
    <select id="selectAll" resultType="student">

        select * from student

    </select>

    <select id="selectOne" resultType="clazz">

        select * from clazz where clazzno=#{param1}

    </select>


    <!--N+1-->
    <select id="selectAll2" resultMap="rm1">

        select * from student

    </select>
    <resultMap id="rm1" type="student">


        <!--  主键使用 <id></id>
              其他列使用 <result></result>

              如果数据库列名和实体类属性名一致1,2,3可以省略,但公共字段不建议省略,即第三个:clazzno为student和clazz表的公共字段

        -->
        <id column="sid" property="sid"></id>  <!--1-->
        <result column="sname" property="sname"></result>  <!--2-->
        <result column="clazzno" property="clazzno"></result>  <!--3-->

        <!--
              select:调用的方法
              column:希望数据库的哪一列作为参数
              javaType:返回值类型
              property:将返回值赋给对象的哪一个属性
        -->
        <association  select="pers.szs.mapper.ClazzMapper.selectOne" column="clazzno" javaType="clazz" property="clazz"></association>

    </resultMap>

    <!--mybatis多表查询SQL-->
    <select id="selectAll3" resultMap="rm2">

        select * from student s join clazz c on s.clazzno=c.clazzno

    </select>

    <resultMap id="rm2" type="student">

        <id column="sid" property="sid"></id>

        <result column="sname" property="sname"></result>
        <result column="clazzno" property="clazzno"></result>



        <association property="clazz" javaType="clazz">

            <id column="clazzno" property="clazzno"></id>
            <result column="cname" property="cname"></result>

        </association>



    </resultMap>

</mapper>

ClazzMapper(Intreface)

package pers.szs.mapper;

import pers.szs.entity.Clazz;
import pers.szs.entity.Student;

import java.util.List;

public interface ClazzMapper {

    //查询所有班级信息
    List<Clazz> selectAll();

    List<Clazz> selectAll2();

    List<Clazz> selectAll3();

    //按照班级编号查询学生信息
    List <Student> selectMore(int clazzno);

    //按照指定编号查询班级信息
    Clazz selectOne(int clazzo);


}

ClazzMapper.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="pers.szs.mapper.ClazzMapper">

<select id="selectOne" resultType="clazz">

    select * from clazz where clazzno=#{param1}

</select>

    <!--业务代理方式-->
    <select id="selectAll" resultType="clazz">

        select * from clazz

    </select>

    <select id="selectMore" resultType="student">

        select * from student where clazzno=#{param1}

    </select>

    <!--N+1-->
    <select id="selectAll2" resultMap="rm1">

        select * from clazz

    </select>


    <resultMap id="rm1" type="clazz">

        <id column="clazzno"  property="clazzno"></id>
        <result column="cname" property="cname"></result>

        <collection select="pers.szs.mapper.StudentMapper.selectMore" column="clazzno" ofType="student" property="list"></collection>

    </resultMap>

    <!--mybatis中的多表查询SQL-->
    <select id="selectAll3" resultMap="rm2">

        select * from student s join clazz c on s.clazzno=c.clazzno

    </select>

    <resultMap id="rm2" type="clazz">

        <id column="clazzno" property="clazzno"></id>
        <result column="cname" property="cname"></result>

        <collection property="list" ofType="student">

            <id column="sid" property="sid"></id>

            <result column="sname" property="sname"></result>
            <result column="clazzno" property="clazzno"></result>

        </collection>


    </resultMap>

</mapper>

1.业务代码的方式(完全通过Java代码来实现多表查询)

(通过查询学生信息获取clazzno,再通过clazzno来查询班级信息)

package pers.szs.test;

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 pers.szs.entity.Clazz;
import pers.szs.entity.Flower;
import pers.szs.entity.Student;
import pers.szs.mapper.ClazzMapper;
import pers.szs.mapper.FlowerMapper2;
import pers.szs.mapper.StudentMapper;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class TestB {
    public static void main(String[] args) throws IOException {

        //解析mybatis.xml文件
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");


        //创建sqlSession工厂

        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        //创建sqlSession对象

          //openSession(bool b) b默认为false:事务不会自动提交(即update,delete,insert操作不会自动提交至数据库,会保存到内存中,需要手动提交)
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        //调用方法

        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        ClazzMapper clazzMapper = sqlSession.getMapper(ClazzMapper.class);


        List<Student> studentList = studentMapper.selectAll();

        for(Student student:studentList){

            Integer clazzno = student.getClazzno();

            Clazz clazz = studentMapper.selectOne(clazzno);

            System.out.println(student+"--->"+clazz);


        }

        System.out.println("===================================================================================");

        for(Student student:studentList){

            Integer clazzno = student.getClazzno();

            Clazz clazz = studentMapper.selectOne(clazzno);

            student.setClazz(clazz);

            System.out.println(student);

        }


        //关闭资源

        sqlSession.close();

    }
}

(通过查询班级信息获取clazzno,再通过clazzno来查询学生信息)

package pers.szs.test;

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 pers.szs.entity.Clazz;
import pers.szs.entity.Student;
import pers.szs.mapper.ClazzMapper;
import pers.szs.mapper.StudentMapper;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class TestC {
    public static void main(String[] args) throws IOException {

        //解析mybatis.xml文件
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");


        //创建sqlSession工厂

        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        //创建sqlSession对象

          //openSession(bool b) b默认为false:事务不会自动提交(即update,delete,insert操作不会自动提交至数据库,会保存到内存中,需要手动提交)
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        //调用方法

        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        ClazzMapper clazzMapper = sqlSession.getMapper(ClazzMapper.class);

        List<Clazz> clazzList = clazzMapper.selectAll();
        for(Clazz clazz:clazzList){

            Integer clazzno = clazz.getClazzno();
            List<Student> studentList = clazzMapper.selectMore(clazzno);

            System.out.println(clazz+"--->"+studentList);
        }


        System.out.println("=========================================================================================");


        for(Clazz clazz:clazzList){
            Integer clazzno = clazz.getClazzno();

            List<Student> studentList = clazzMapper.selectMore(clazzno);

            clazz.setList(studentList);

            System.out.println(clazz);

        }


        //关闭资源

        sqlSession.close();

    }
}

2.N+1方式

(查询学生所有信息,包括clazz属性)

package pers.szs.test;

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 pers.szs.entity.Clazz;
import pers.szs.entity.Student;
import pers.szs.mapper.ClazzMapper;
import pers.szs.mapper.StudentMapper;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class TestD {
    public static void main(String[] args) throws IOException {

        //解析mybatis.xml文件
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");


        //创建sqlSession工厂

        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        //创建sqlSession对象

          //openSession(bool b) b默认为false:事务不会自动提交(即update,delete,insert操作不会自动提交至数据库,会保存到内存中,需要手动提交)
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        //调用方法

        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        ClazzMapper clazzMapper = sqlSession.getMapper(ClazzMapper.class);


        List<Student> studentList = studentMapper.selectAll2();
        System.out.println(studentList);
        //关闭资源

        sqlSession.close();

    }
}

(查询班级所有信息,包括list属性)

package pers.szs.test;

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 pers.szs.entity.Clazz;
import pers.szs.entity.Student;
import pers.szs.mapper.ClazzMapper;
import pers.szs.mapper.StudentMapper;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class TestE {
    public static void main(String[] args) throws IOException {

        //解析mybatis.xml文件
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");


        //创建sqlSession工厂

        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        //创建sqlSession对象

          //openSession(bool b) b默认为false:事务不会自动提交(即update,delete,insert操作不会自动提交至数据库,会保存到内存中,需要手动提交)
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        //调用方法

        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        ClazzMapper clazzMapper = sqlSession.getMapper(ClazzMapper.class);


        List<Clazz> clazzList = clazzMapper.selectAll2();
        System.out.println(clazzList);
        //关闭资源

        sqlSession.close();

    }
}

  1. 多表查询SQL
package pers.szs.test;

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 pers.szs.entity.Clazz;
import pers.szs.entity.Flower;
import pers.szs.entity.Student;
import pers.szs.mapper.ClazzMapper;
import pers.szs.mapper.FlowerMapper2;
import pers.szs.mapper.StudentMapper;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class TestF {
    public static void main(String[] args) throws IOException {

        //解析mybatis.xml文件
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");


        //创建sqlSession工厂

        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        //创建sqlSession对象

          //openSession(bool b) b默认为false:事务不会自动提交(即update,delete,insert操作不会自动提交至数据库,会保存到内存中,需要手动提交)
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        //调用方法

        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        ClazzMapper clazzMapper = sqlSession.getMapper(ClazzMapper.class);

        List<Student> studentList = studentMapper.selectAll3();
        System.out.println(studentList);

        System.out.println("====================================================================================");
        List<Clazz> clazzList = clazzMapper.selectAll3();
        System.out.println(clazzList);


        //关闭资源

        sqlSession.close();

    }
}

学到这里大家可能会发现一个问题,每次书写Test类时都要反复书写重样的内容,包括解析mybatis.xml文件等,那么我们如何对现有的代码进行优化?

第四部分(代码优化)

优化方案一:提取工具类

工具类

package pers.szs.util;

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 pers.szs.entity.Clazz;
import pers.szs.entity.Student;
import pers.szs.mapper.ClazzMapper;
import pers.szs.mapper.StudentMapper;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class DBUtil {


    //解析mybatis.xml文件
    private static SqlSessionFactory sqlSessionFactory=null;
   static {

        InputStream resourceAsStream;

        {
            try {
                resourceAsStream = Resources.getResourceAsStream("mybatis.xml");

                 sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    public static SqlSession getSqlSession(){


        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        return sqlSession;

    }



}

测试类

package pers.szs.test;

import pers.szs.entity.Student;
import pers.szs.mapper.StudentMapper;
import pers.szs.util.DBUtil;

import java.util.List;

public class TestG {

    public static void main(String[] args) {


        StudentMapper studentMapper = DBUtil.getSqlSession().getMapper(StudentMapper.class);


        List<Student> studentList = studentMapper.selectAll3();
        System.out.println(studentList);
    }
}

经过优化我们可以发现,测试类的代码已经大大减少,但是这仍然不是最终方案,因为我们会发现,如果用户提出一个请求需要我们查询需要后台查询所有学生和班级的信息,测试类如下:

package pers.szs.test;

import pers.szs.entity.Clazz;
import pers.szs.entity.Student;
import pers.szs.mapper.ClazzMapper;
import pers.szs.mapper.StudentMapper;
import pers.szs.util.DBUtil;

import java.util.List;

public class TestG {

    public static void main(String[] args) {

           selectA();
        
    }
    
    public static void selectA(){

        StudentMapper studentMapper = DBUtil.getSqlSession().getMapper(StudentMapper.class);

        List<Student> studentList = studentMapper.selectAll3();
        System.out.println(studentList);
        
        selectB();

    }
    
    public static void selectB(){
        ClazzMapper clazzMapper=DBUtil.getSqlSession().getMapper(ClazzMapper.class);
        List<Clazz> clazzList = clazzMapper.selectAll3();
        System.out.println(clazzList);

    }
}

通过测试类我们可以发现,每查询一个数据库表的信息,我们就需要使用Dbutil获取一个SqlSession对象,这样无形中造成了sqlSession对象的浪费,为此我们对DBUtil类进行优化

优化方案二:ThreadLocal 作用:在同一个线程中实现数据(sqlSession)的共享

​ 底层使用的map集合:map.put(key,value)

​ map.put(线程ID,conn)

package pers.szs.util;

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 pers.szs.entity.Clazz;
import pers.szs.entity.Student;
import pers.szs.mapper.ClazzMapper;
import pers.szs.mapper.StudentMapper;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class DBUtil {


    //解析mybatis.xml文件
    private static SqlSessionFactory sqlSessionFactory;

    //创建ThreadLocal对象
    private static ThreadLocal<SqlSession> tl=new ThreadLocal<>();

   static {

        InputStream resourceAsStream;

        {
            try {
                resourceAsStream = Resources.getResourceAsStream("mybatis.xml");

                 sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static SqlSession getSqlSession(){


       //获得ThreadLocal中的SqlSession对象
       SqlSession sqlSession=tl.get();

       if(sqlSession==null){

           sqlSession = sqlSessionFactory.openSession(true);

           //把创建好的对象放到ThreadLocal中
           tl.set(sqlSession);
       }



        return tl.get();

    }


   //关闭sqlSession
    public static void closeAll(){

        SqlSession sqlSession = tl.get();

        if(sqlSession!=null){
            sqlSession.close();
        }

        tl.set(null);
    }
}

测试类:TestG

package pers.szs.test;

import pers.szs.entity.Clazz;
import pers.szs.entity.Student;
import pers.szs.mapper.ClazzMapper;
import pers.szs.mapper.StudentMapper;
import pers.szs.util.DBUtil;

import java.util.List;

public class TestG {

    public static void main(String[] args) {

           selectA();
    }


    public static void selectA(){

        StudentMapper studentMapper = DBUtil.getSqlSession().getMapper(StudentMapper.class);

        List<Student> studentList = studentMapper.selectAll3();
        System.out.println(studentList);
        DBUtil.closeAll();

        selectB();

    }

    public static void selectB(){
        ClazzMapper clazzMapper=DBUtil.getSqlSession().getMapper(ClazzMapper.class);
        List<Clazz> clazzList = clazzMapper.selectAll3();
        System.out.println(clazzList);

        DBUtil.closeAll();

    }
}

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: MyBatis是一个流行的持久层框架,它可以将SQL语句和Java对象之间的映射关系定义在XML文件或注解中,并提供了丰富的查询语言和灵活的参数绑定方式。在使用MyBatis进行数据操作时,有时会遇到插入唯一异常的问题,下面让我们一起来看看如何解决这个问题。 1. 异常描述 当我们向数据库插入一条记录时,如果违反了唯一性约束,就会抛出插入唯一异常,如下所示: ``` ### Error updating database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'xxx' for key 'name_unique' ### The error may involve com.example.mapper.UserMapper.insert-Inline ### The error occurred while setting parameters ### SQL: insert into user(name, age) values (?, ?) ### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'xxx' for key 'name_unique' ``` 其中,'xxx'表示违反唯一性约束的值,'name_unique'表示违反唯一性约束的字段名。 2. 解决方法 为了避免插入唯一异常,我们可以采取以下两种解决方法: 2.1 使用INSERT IGNORE语句 在MySQL中,可以使用INSERT IGNORE语句来向表中插入记录,如果遇到违反唯一性约束的情况,就会忽略该记录,而不是抛出异常。因此,我们可以将MyBatis的插入语句改为INSERT IGNORE语句,如下所示: ``` <insert id="insertUser" parameterType="com.example.entity.User"> INSERT IGNORE INTO user(name, age) VALUES (#{name}, #{age}) </insert> ``` 2.2 使用ON DUPLICATE KEY UPDATE语句 在MySQL中,还可以使用ON DUPLICATE KEY UPDATE语句来向表中插入记录,如果遇到违反唯一性约束的情况,就会更新该记录,而不是抛出异常。因此,我们可以将MyBatis的插入语句改为ON DUPLICATE KEY UPDATE语句,如下所示: ``` <insert id="insertUser" parameterType="com.example.entity.User"> INSERT INTO user(name, age) VALUES (#{name}, #{age}) ON DUPLICATE KEY UPDATE age = #{age} </insert> ``` 其中,ON DUPLICATE KEY UPDATE语句指定了更新操作的字段和值,这里我们只更新了年龄字段。 以上就是解决MyBatis插入唯一异常的两种方法,根据具体情况选择适合自己的方法即可。 ### 回答2: 在使用MyBatis进行插入操作时,可能会遇到插入唯一异常。该异常通常是由于数据库表的唯一约束导致的。 当我们向数据库表插入数据时,如果违反了唯一约束,数据库将抛出异常,表示插入失败。常见的唯一约束有主键约束、唯一索引等。 解决这个问题的方法有两种: 1. 在程序中进行唯一性校验:在执行插入操作之前,可以先查询数据库中是否已存在相同的数据。如果已存在,则不进行插入操作,避免了唯一异常的发生。这种方法比较消耗数据库资源,但可以保证数据的唯一性。 2. 使用数据库的"insert ignore"或"insert on duplicate key update"语句:这种方法是在插入操作时,使用特殊的语句来处理唯一异常。"insert ignore"语句会即使发生唯一异常,也不会抛出异常,而是直接忽略这条插入数据;"insert on duplicate key update"语句则是在发生唯一异常时,执行更新操作。这种方法相对较为简洁高效,但需要根据数据库的不同进行调整。 总结来说,解决MyBatis插入唯一异常的方法有多种,可以通过程序中进行唯一性校验,或者使用特殊的数据库插入语句来处理。需要根据具体情况选择最合适的方法来解决唯一异常问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路上阡陌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值