在学习MyBatis之前先了解一下什么是Mybatis?它能解决什么问题?
什么是 MyBatis?
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。
Mybatis解决什么问题?
MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
JDBC和Mybatis使用对比
JDBC
java
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
<?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
<?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>
主程序:
java
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: 无参查询
xml
<select id="demo1" resultType="com.czy.model.User">
select * from user
</select>
demo2: 有参查询
xml
<select id="demo2" parameterType="int" resultType="com.czy.model.User">
select * from user where id = #{id}
</select>
注:参数符号#{}
demo3: 多参查询,UserQuery对象有id和name属性
xml
<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属性
xml
<select id="demo6" resultType="com.czy.model.User">
select * from user
</select>
注:期望从这条语句中返回结果的类全限定名或别名。注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。resultType 和 resultMap 之间只能同时使用一个。
Select元素,resultMap属性
xml
<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属性
xml
<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增加缓存配置,相关配置下面详解
xml
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
mybatis-config.xml增加下面配置,用于开启全局二级缓存,默认是true,开启二级缓存
xml
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
Select元素,flushCache属性
xml
<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属性
xml
<!-- 插入的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赋值
xml
<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 元素中定义不同的参数值。
简单用法:
xml
<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
高级用法:
xml
<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
html
解读: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}"
xml
<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没多大区别
xml
<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>
至此入门篇完结!!有什么问题的宝子们可以留言!!