Bootstrap

Mybatis入门

在学习MyBatis之前先了解一下什么是Mybatis?它能解决什么问题?

什么是 MyBatis?

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。

Mybatis解决什么问题?

MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

JDBC和Mybatis使用对比

JDBC
		Class.forName("com.mysql.cj.jdbc.Driver");
        Connection connection = DriverManager.getConnection("url",username", "password");
        PreparedStatement preparedStatement = connection.prepareStatement("select * from user");
        ResultSet resultSet = preparedStatement.executeQuery();
        List<User> users = new ArrayList<>();
        while (resultSet.next()) {
            User user = new User();
            // 第一种方式,通过列的下标去获取数据
            int id = resultSet.getInt(1);
            // 第二种方式通过列名获取数据
            //resultSet.getInt("id")
            user.setId(id);
            String name = resultSet.getString(2);
            user.setName(name);
            int age = resultSet.getInt(3);
            user.setAge(age);
            users.add(user);
        }
        users.forEach(System.out::println);
        resultSet.close();
        preparedStatement.close();
        connection.close();

缺点:
1、每次链接数据库,基本上connect对象、preparedStatement 、resultSet对象都需要人工维护,而且每次用完都需要进行cloes
2、获取到resultSet对象虽然可以通过两种方式去获取相应信息,但存在获取字段类型不对而导致程序异常,数据查询失败
3、数据库字段给实体对象赋值过去麻烦,也存在赋错值的情况。

mybatis

配置:

<?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"></properties>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${database.driver}"/>
                <property name="url" value="${database.url}"/>
                <property name="username" value="${database.username}"/>
                <property name="password" value="${database.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>

usermapper配置:

<?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="userMapper">
    <select id="selectUser" parameterType="int" resultType="com.czy.model.User">
        select * from user
    </select>
</mapper>

主程序:

		String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = sqlSessionFactory.openSession();
        try{
            List<User> users = session.selectList("userMapper.selectUser");
            users.forEach(user -> {
                System.out.println(user.toString());
            });
        }finally {
            session.close();
        }

优势:
1、通过配置减少connect相关链接代码
2、在usermapper中可以写我们熟悉的sql语句
3、可以指定resultType的实体类型,省去实体赋值等等
4、主程序通过mapper中定义的namespace+’.’+select元素的id来找到需要执行的sql语句。

mybatis基础知识

mybatis官方文档写得比较全面,小白易上手,也有中文版:https://mybatis.org/mybatis-3/zh_CN/index.html下面只针对官网中的“XML 映射器”进行案例教程。

XML映射器

MyBatis 的真正强大在于它的语句映射,这是它的魔力所在。由于它的异常强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 致力于减少使用成本,让用户能更专注于 SQL 代码。
SQL 映射文件只有很少的几个顶级元素(按照应被定义的顺序列出):

  • cache – 该命名空间的缓存配置。
  • cache-ref – 引用其它命名空间的缓存配置。
  • resultMap – 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。
  • parameterMap – 老式风格的参数映射。此元素已被废弃,并可能在将来被移除!请使用行内参数映射。文档中不会介绍此元素。
  • sql – 可被其它语句引用的可重用语句块。
  • insert – 映射插入语句。
  • update – 映射更新语句。
  • delete – 映射删除语句。
  • select – 映射查询语句。

Select元素

demo1: 无参查询
<select id="demo1" resultType="com.czy.model.User">
        select * from user
</select>
demo2: 有参查询
<select id="demo2" parameterType="int" resultType="com.czy.model.User">
        select * from user where id = #{id}
</select>

注:参数符号#{}

demo3: 多参查询,UserQuery对象有id和name属性
<select id="demo3" parameterType="com.czy.query.UserQuery" resultType="com.czy.model.User">
        select * from user where name = #{name} and id = #{id}
 </select>

select元素还有其他属性设置,可参考官网:https://mybatis.org/mybatis-3/zh_CN/sqlmap-xml.html#select-1

Select元素,resultType属性

<select id="demo6" resultType="com.czy.model.User">        
   select * from user    
</select>

注:期望从这条语句中返回结果的类全限定名或别名。注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。resultType 和 resultMap 之间只能同时使用一个。

Select元素,resultMap属性

<resultMap id="demo7ResultMap" type="com.czy.model.User">        
  <result property="id" column="id" javaType="Integer" jdbcType="INTEGER"/>   
</resultMap>    
<select id="demo7" resultMap="demo7ResultMap">        
  select * from user    
</select>

注:执行结果能和预想的有些出入,预想中是User实体只给id赋值,结果你会发现User其它属性也有值,这是为什么呢?
其实是autoMapping属性起到的作用,MyBatis 将会为本结果映射开启或者关闭自动映射。这个属性会覆盖全局的属性 autoMappingBehavior,如果没有设置的话则会延用autoMappingBehavior配置autoMappingBehavior默认值“PARTIAL”:PARTIAL 只会自动映射没有定义嵌套结果映射的字段。

Select元素,statementType属性

可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
三者区别:
Statement‌适用于执行简单的、不带参数的查询操作,如执行一次性的查询任务。
PreparedStatement‌适用于需要频繁执行相同SQL语句的场景,如插入、更新、删除操作,能够有效提高性能并防止SQL注入。
CallableStatement‌适用于需要调用数据库存储过程的情况,特别是当存储过程涉及复杂的逻辑处理和参数交互时。

Select元素,cache属性

<select id="demo4" useCache="true" parameterType="int" resultType="com.czy.model.User">        
  select * from user where id = #{id}    
</select>

设置cache为true,则该查询开启了缓存,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true。
注:只是单纯将useCache=true也是无法使用二级缓存,需增加一下配置:

在Mapper.xml增加缓存配置,相关配置下面详解

<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>

mybatis-config.xml增加下面配置,用于开启全局二级缓存,默认是true,开启二级缓存

<settings>
  <setting name="cacheEnabled" value="true"/>
</settings>

Select元素,flushCache属性

<select id="demo5" useCache="true" parameterType="int" flushCache="true" resultType="com.czy.model.User">        
  select * from user where id = #{id} 
</select>

说明:将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。不管useCache为true,缓存也是不生效

insert、delete、update元素

  • id:在命名空间中唯一的标识符,可以被用来引用这条语句。
  • parameterType:将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以根据语句中实际传入的参数计算出应该使用的类型处理器(TypeHandler),默认值为未设置(unset)。
  • parameterMap:用于引用外部 parameterMap 的属性,目前已被废弃。请使用行内参数映射和parameterType 属性。
  • flushCache:将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:(对 insert、update 和 delete 语句)true。
  • timeout:这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)依赖数据库驱动。
  • statementType:可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
  • useGeneratedKeys:仅适用于 insert 和 update)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段),默认值:false。
  • keyProperty:(仅适用于 insert 和 update)指定能够唯一识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset)。如果生成列不止一个,可以用逗号分隔多个属性名称。
  • keyColumn:(仅适用于 insert 和 update)设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称。
  • databaseId:如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略。

insert、update元素,useGeneratedKeys、keyProperty属性

<!-- 插入的user对象执行完后,user对象id是null值-->    
<insert id="demo8" useGeneratedKeys="true">        
  insert into user (name,age) values(#{name},#{age});   
</insert>
<!-- 插入的user对象执行完后,user对象id是有值,原因在于keyProperty ,会从useGeneratedKeys生成的id赋值给id属性-->       
<insert id="demo9" useGeneratedKeys="true" keyProperty="id">       
  insert into user (name,age) values(#{name},#{age});   
</insert>

selectKey元素

selectKey元素解决我们自定义主键功能。下面例子是通过生成一个0~100的随机整数给ID赋值

<insert id="demo10">        
     <selectKey keyProperty="id" resultType="int" order="BEFORE">            
       -- 0~100之间随机整数            
       select round(100*rand(),0)       
     </selectKey>        
     insert into user (name,age) values(#{name},#{age});    
  </insert>

selectKey相关属性说明:

  • keyProperty:selectKey 语句结果应该被设置到的目标属性。如果生成列不止一个,可以用逗号分隔多个属性名称。
  • keyColumn:返回结果集中生成列属性的列名。如果生成列不止一个,可以用逗号分隔多个属性名称。
  • resultType:结果的类型。通常 MyBatis 可以推断出来,但是为了更加准确,写上也不会有什么问题。MyBatis 允许将任何简单类型用作主键的类型,包括字符串。如果生成列不止一个,则可以使用包含期望属性的 Object 或 Map。
  • order:可以设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它首先会生成主键,设置 keyProperty 再执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 中的语句 - 这和 Oracle 数据库的行为相似,在插入语句内部可能有嵌入索引调用。
  • statementType:和前面一样,MyBatis 支持 STATEMENT,PREPARED 和 CALLABLE 类型的映射语句,分别代表 Statement, PreparedStatement 和 CallableStatement 类型。

sql元素

这个元素可以用来定义可重用的 SQL 代码片段,以便在其它语句中使用。参数可以静态地(在加载的时候)确定下来,并且可以在不同的 include 元素中定义不同的参数值。

简单用法:

<sql id="demo11SQL"> id,name</sql>    
<select id="demo11" resultType="com.czy.model.User">
        select <include refid="demo11SQL"/> from user    
</select>

执行结果:==> Preparing: select id,name from user

高级用法:

<sql id="sometable">  ${prefix}Table</sql>
<sql id="someinclude">  
  from <include refid="${include_target}"/>
</sql>
<select id="demo12" resultType="map">  
  select field1, field2, field3  
  <include refid="someinclude">    
    <property name="prefix" value="Some"/>    
    <property name="include_target" value="sometable"/> 
   </include>
</select>

执行结果SQL: select field1, field2, field3 from SomeTable

解读:include标签定义两个属性,name:prefix value:Some 和name:include_target value:sometable  refid指向sql元素id=someinclude  ;而sql元素id=someinclude中又包含一个include标签refid=${include_target},${include_target}是在select标签中的include标签定义的属性value=sometable,所以 id=someinclude中的refid实际上是sometable,一层层嵌套

ResultMap高级用法,association子查询

一个复杂类型的关联;许多结果将包装成这种类型嵌套结果映射 – 关联可以是 resultMap 元素,或是对其它结果映射的引用
注:association只适用一对一的关系,多个参数关联查询可以写column= “{prop1=col1,prop2=col2}”

<resultMap id="demo15ResultMap" type="com.czy.model.User">        
  <association property="blog" column="id" javaType="com.czy.model.Blog" select="demo15BlogSelect"/>
  <!-- 多参子查询        <association property="blog" column="{id=id,title=name}" javaType="com.czy.model.Blog" select="demo15BlogSelect"/>        -->    
</resultMap> 
   
<select id="demo15BlogSelect" resultType="com.czy.model.Blog">        
    select * from blog where user_id = #{id}        
    -- 多参子查询        
    -- select * from blog where user_id = #{id} and title = #{title}    
 </select>    
 <select id="demo15" resultMap="demo15ResultMap">        
   select * from user    
 </select>

ResultMap高级用法,collection子查询

一个复杂类型的集合嵌套结果映射 – 集合可以是 resultMap 元素,或是对其它结果映射的引用
注:collection适用一对多的关系,多个参数关联查询可以写column= “{prop1=col1,prop2=col2}”用法和association没多大区别

<resultMap id="demo14ResultMap" type="com.czy.model.User">        
   <collection property="blogs" javaType="ArrayList" column="id" ofType="com.czy.model.Blog" select="demo14BlogSelect"/>    
</resultMap>    
<select id="demo14BlogSelect" resultType="com.czy.model.Blog">        
 select * from blog where user_id = #{id}    
</select>    
<select id="demo14" resultMap="demo14ResultMap">        
 select * from user    
</select>

至此入门篇完结!!有什么问题的宝子们可以留言!!

案例具体代码:https://gitee.com/zeyc/mybatis

;