MyBatis概要


前言

1、web项目的三层架构:
    ①界面层:用于接受用户的数据,返回数据的处理结果
    ②业务处理层:用来计算处理用户的数据,调用数据库
    ③持久层(数据访问层):连接数据库进行增删改查(CRUD)

2、层级关系:用户使用界面===>业务处理层===>数据访问层===>数据库


3、为了简便程序的开发,每一层都有对应的实现框架
      界面层:springmvc,
      数据访问层:spring,主要技术ioc,aop
      持久层:mybatis,动态sql,传参,返回值类型


一、mybatis概述

一个简化数据库增删改查操作的,十分实用的框架,而且还可以与spring,springmvc等框架整合使用,降低了程序的开发难度和减少了代码的冗余

二、利用Maven构建一个简单的mybatis实现(IDEA)

1.在IDEA中配置maven工具


在这里插入图片描述

2.新建java项目

在新建的项目中选中maven,再选中archetype,勾选quickstart,构架一个java项目(因为只是一个简单的测试mybatis的,不需要构建web项目),然后修改pom文件的内容,需要导入mybatis的依赖,和对应JDBC的依赖,还需要能够加载映射文件的插件。

< groupId>org.mybatis< /groupId>
< artifactId>mybatis< /artifactId>
< version>3.5.1< /version>
<
< groupId>mysql< /groupId>
< artifactId>mysql-connector-java< /artifactId>
< version>8.0.13< /sersion>//如果是mysql5的话,那么使用5.0+的版本
<
< build>
< resources>
< resource>
< directory>src/main/java< /directory>
表示在什么样的目录下的什么文件需要拷贝到classes目录下
< include>/*.properties< /include>
< include>
/*.xml< /include>
< /includes>
< filtering>false< /filtering>
< /resource>
< /resources>
< /build>

3.新建接口cn.edu.hbpu.dao.StudentDao和sql配置文件

StudentDao.java

public interface StudentDao {
    List<Student> selectStudents();

    int insertStudents(Student student);
}

StudentDao.xml

<?xml version="1.0" encoding="UTF-8" ?> PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

< mapper namespace=“com.test.dao.StudentDao”>
< select id=“selectStudents” resultType=“com.test.domain.Student”>
select * from student
< /select>
< insert id=“insertStudents”>
insert into student values(#{id},#{name},#{email},#{age})
< /insert>
< /mapper>

      SQL映射文件标签解读:
         1)namespace
                 标识当前sql映射文件的命名空间,赋值dao层中的接口的全限定名称,
         2)select/insert/update/delete
             eg:<insert id="唯一标识,不能重复与接口中的方法名对应"><insert/>

4.创建mybatis主配置文件

在resoruces文件夹下面创建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><!--当前xml文件的根标签-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"></setting>
    </settings>
    <environments default="development"><!--数据库的配置信息,default的值必须和一个具体的数据库的id值相同-->
        <environment id="development"><!--一个具体的数据库的配置信息-->
            <transactionManager type="JDBC"/><!--当前使用的事务类型,基本上都是JDBC(也就是Connection对象的commit,rollback的事务类型)-->
            <dataSource type="POOLED"><!--数据源,都是使用的POOLED(连接池)-->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/><!--具体的连接信息-->
                <property name="url" value="jdbc:mysql://localhost:3306/student?useSSL=false&amp;serverTimezone=UTC"/>
                <property name="username" value="****"/>
                <property name="password" value="****"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/test/dao/mapper.xml"/>

        <!--        可以指定多个mapper-->
    </mappers>
</configuration>

主配置文件解读:
1、settings标签标识在控制台输出mybatis执行的过程
2、mappers标签指定sql映射文件的位置,如果mapper指定,路径的分隔符不能使用.

5.创建测试类

public class testInsert {
    @Test
    public void insertStudents() throws IOException {
        String config = "main.xml";

        //2.读取这个主配置文件
        InputStream in = Resources.getResourceAsStream(config);

        //3.创建SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

        //4.创建SqlSessionFactory对象
        SqlSessionFactory factory = builder.build(in);

        //5.获取SqlSession,从SqlSessionFactory中获取
        SqlSession sqlSession = factory.openSession();

        //6.指定要执行的sql语句的表示,也就是sql映射文件中的namespace+"."+标签的id值
        String sqlId = "com.test.mybatis01.dao.StudentDao"+"."+"insertStudents";

        //7.执行sql语句
        int res = sqlSession.insert(sqlId,new Student(1004,"张飞","432@sina.com",15));
        sqlSession.commit();

        //8.输出/处理结果
        System.out.println("影响数据库的记录条数"+res);

        //9.关闭sqlSession对象
        sqlSession.close();
    }
}

1、创建sqlSession对象默认是不自动提交事务的。需要自动手动提交(适合事务),或者设置自动提交(适合单表操作或者查询操作)。SqlSessionFactory.openSession(true)
2、sql映射文件中的sql语句必须与接口中的方法保持一致

3、我们也可以使用SqlSession中的getMapper(Class classz),这样可以对应dao接口的实现类,不用我们自己创建接口的实现类,在完成数据库操作之后,记得关闭sqlSession对象


三、参数类型

也就是sql映射文件中sql语句中的parameterType标签:因为可以通过反射机制获取到参数的类型,所以不需要我们指定。
1、一个参数:
      简单参数类型直接传参即可,在sql语句中使用#{参数名}进行调用,实测:其实对于只有一个参数的情况来说,参数名可以是任意的,但是如果使用${}占位符进行调用那么必须和参数必须加上注解才能使用

2、多个参数解决方法:
     ①使用注解:@param(“id”),使用#/${}可以直接调用
     ②对象,将所有的属性封装在一个类中,使用#/${属性名}即可调用,(完整的是#{属性名,javaType=“java中数据类型”,jdbcType=“数据库中数据类型”})
     ③使用map,将参数信息以键值对的方式存储在map集合中,使用#/${属性名}即可调用
     ④使用list/array,与后面的动态sql中foreach语句有关
     ⑤使用参数的索引,在mybatis3.3之前使用#{0/1/2},在mybatis3.3(包括)之后使用#{arg0/1/2}

※$和#的区别:
   #:使用这个占位符,mybatis会使用PreparedStatement对象预编译sql语句,然后执行sql,这样可以达到一次编译,多次执行的效果,效率搞,而且sql语句中使用?占位符作为参数。可以防止sql注入现象
   $:使用这个占位符,mybatis会使用Statement对象,执行sql,对于sql语句完全是字符串的拼接操作,这样会导致sql注入现象,eg:sql = "select * from student where id =  +"1 or 1 = 1"";但是如果只是代表一些与数据无关的字段名/表名

四、返回值类型

如果我们在使用select语句,那么可能只有一个记录(max,min),也可能只有一条记录,或者多条记录,这时候就需要我们指定返回值的类型的。
1、如果只有一个记录值(假如是int类型),那么我们就只需要使用java.lang.Integer作为resultType的值,也可以直接使用int(Integer的别名),
2、多行或者一行:
①可以将数据存储在一个实体类中的,这时也需要写类的全限定名称(我们也可以为类取别名,在mybatis主配置文件中)

    <typeAliases>
        <typeAlias type="com.test.domain.Student" alias="studnet"/>
        <package name="com.test"></package>
    </typeAliases>

第一条语句代表为指定类取别名,第二条代表为包下面的所有类取别名,不区别大小写,我们也可以使用@Alias注解自定义类名,即在resultType中可以写student,也可以是sTudenT,值得注意的是,字段名和属性名同名,因为mybatis是调用set+字段名(不区分大小写)的方法给属性赋值的,所以set方法也是不可缺的,但是如果我们set方法没有形参,那么无论我们怎么给属性赋值,属性的值都是和对应字段名的值相同,只有形参存在时,我可以改变属性的赋值
②使用map:可以将数据中的字段名作为key,数据作为value存储在map对象中,resultType=“java.util.HashMap”
③resultType
如果实体类的属性名和字段名不相同的话可以采用map,也可以采用resultMap(和resultType不能共存),用户指顶属性名和字段名存储关系
在当前文件下定义标签

< resultMap id=“stu” type=“com.test.domain.Stu”>
< id column=“id” property=“myId” />
< result column=“name” property=“myName” />
< result column=“email” property=“myName” />
< result column=“age” property=“myAge”/>
</ resultMap>
关于实体类中的属性和字段名不等的情况,可以在sql语句中采用取别名的方法。但是耦合度高,不建议使用

五、动态sql

为了更加简便sql语句的书写,比如根据id查询和根据name查询,完全是条件的不同。
1、if标签
select * from student where 1 = 1
< if test="#{id} != null">
and id = #{id}
< /if>
< if test="@{#{name} != ‘’ || #{name} !=null}">
and name = #{name}
< /if>
缺点,我们需要自己完成字符串的拼接,而且不适合多个判断语句的书写,where后面必须加上恒等条件
2、where标签

 < where>
 < if test="#{name} != null && #{name} !='' ">
      name = #{name}
  < /if>
 < if test="#{id} != null">
      and id = #{id}
 < /if>
 < if test="#{address} != null">
      and address = #{address}
< /if>
 < /where>
 解决if的存在的弊端,如果后面的if条件都不成立,那么没有where判断,如果存在多个条件的连接那么会自动的去掉第一个字符串前面的or/and,
   

3、foreach标签
主要确定in中的返回判断的,
select * from student where id in
< foreach collection=“array/list” item=“stu” open="(" close=")" separator=",">
stu
< /foreach>
标签中的属性分别表示 集合的类型, 遍历出来的元素的名称,字符串的开始符号, 字符串的结束符号,分隔符
后面还是多一个逗号,所以我们可以)的前面加一个-1,一个根本不存在的数据。
可以简写
select * from student where id in(
< foreach collection=“array/list” item=“stu”>
stu,
< /foreach> -1
)

 4、set标签
 用于在update中可以帮我们自动去除多个条件之间的,
 eg:update student set name = ll,age = 20 where id = 2043242
 如果通过if判断,不能够确定一个条件后面是否还有设置,这样肯定就会多出一个,和foreach一样的道理

六、一对多,一对一

1、一对多

如果从数据库中取出来的数据有一对多的关系,例如一个部门下面有多个员工,那么部门这个实体类中应该还存在一个存放员工信息的集合,这样我们就需要使用resultmap指定字段存入到实体类中属性中。

<resultMap id="" type="">
<id column="" property="" />
<result column="" property="" />
<collection>
<id column="" property="" />
<result column="" property="" />
</collection>
</resultMap>

2、一对一

一个实体类中的属性是另一个实体类的引用数据类型,一个具体的员工在一个部门当中
使用association标签

七、缓存

1、一级缓存

mybatis默认就会使用一级缓存,一级缓存是sqlsession级别的,也就是在一次会话中,对于查询的数据,会存入到缓存中,在sqlsession未关闭之前,也就是会话没有结束之前,再一次执行相同的sql时,不会从数据库中查询,而是从缓存中取出
缓存失效的情况:手动清空缓存,执行了增删改操作,查询语句不一致

2、二级缓存

原理:一次会话结束之后,缓存中的数据就会清空,对于第二会话中相同的查询,还是会继续从数据库中获取,所以二级缓存就是在一次会话结束后,sqlsession关闭的时候,将一级缓存中的数据存入到二级缓存中,每一个mapper都对应一个二级缓存,所以二级缓存是mapper级别的。

存在问题:如果mapperA中有涉及到mapperA和mapperB的查询,但是mapperB执行了增删改操作,由于每一个mapper对应一个二级缓存,在mapperA中,显然是没有修改过数据,所以查询的数据是mapperB未增删改之前的数据,而不是更新后的数据

实现:在mapper配置文件中加入cache标签,属性可以自己配置,如果readOnly设置为true,需要设置实体类可序列化(实现Serializable接口),取出来的对象是相等的。如果为false,返回的是一个新的对象,但是属性是相同的。
在主配置文件中加入setting设置,开启全局缓存。

3、缓存原理

执行查询操作时,首先会从二级缓存中获取,如果没有找到,那么从一级缓存中获取数据,也没有的话,才会执行sql语句连接数据库查询,然后将数据存储到一级缓存中,会话完成之后,更新二级缓存中的内容。

八、其他

1.主配置文件设置的补充

1.settings设置:
①打印日志
②设置数据库中的字段名以驼峰命名法映射到实体类中的属性名,

③设置实体类的别名
④开启全局缓存
2.主配置文件的数据库连接说明

此标签需要指定数据库的事务类型,可选JDBC/managed,表示采用JDBC中Connection的commit,rollback方式。可选Managed,把事务交给一个容器(服务器软件,框架)
< dataSource type="">
此标签表示使用连接池,type=“POOLED”,即使用连接池类PooledDataSource,创建的connection会存储在连接池中,以供下次使用,type=“UPOOLED”,表示不适用连接池,也会创建一个UnPooledDataSource,每次执行sql语句时都会创建一个新的connection对象。

3.数据库属性配置文件
可以将数据库的连接属性存储在properties文件中,在主配置文件中使用标签
< propertes resource="" />导入数据库信息配置文件,如果在类路径下,直接加上文件名就可以了
配置属性名和属性值
< property name=“属性名” value=“属性值”>
使用${属性名进行取用}

4.使用这里需要保证dao接口和xml文件同名,并且在同一个包下,

2.工具类

SqlSessionFactory是一个重量级的类,创建对象要耗费很多的时间,通常创建一次就可以,利用factory对象获取sqlsession对象进行数据库操作, sqlsession是非线程安全的,

public class MyBatisUtil {
    public static SqlSessionFactory factory = null;//静态变量,编译阶段结汇执行.这个变量只需要声明一次就可以了,所以定义为静态变量,

    static{//静态代码块,类加载时就会执行.也就是在编译阶段执行的.
        try {
            InputStream in  = Resources.getResourceAsStream("mybatis.xml");
            factory = new SqlSessionFactoryBuilder().build(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static SqlSession getSqlSession(){
        SqlSession sqlSession = null;
        if(factory!=null){
//            sqlSession = getSqlSession(false);
            sqlSession = factory.openSession();
        }
        return sqlSession;
    }

    public static SqlSession getSqlSession(boolean flag){
        SqlSession sqlSession = null;
        if(null!=factory){
            sqlSession = factory.openSession(flag);
        }
        return sqlSession;
    }
}

3.sql语句的复用

< sql id="">< /sql>,使用标签< include refid=“id” />可以进行字符串的拼接

4.注解式开发

可以直接接口方法上使用注解的形式声明执行的sql语句,对于简单的sql语句更为方便,但是sql语句过于复杂的话,建议使用映射文件。

@Select(),@Update(),@Delete(),@Insert()
连接子查询
@Results(
{@Result(column,property,One=@One(result="")),
@Result(column,property,Many=@Many(result="")
}
)
如果使用动态sql语句,如果使用包裹sql语句

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值