版本:idea2020.1.1 jdk1.8 maven3.6.3
注:本文章摘自Java EE企业级应用开发教程,黑马程序员/编著,仅用于记录学习笔记,分享学习经历。
一、MyBatis核心对象
1、SqlSessionFactory
它是单个数据库映射关系经过编译后的内存镜像,主要作用是创建SqlSession。SqlSessionFactory对象的实例可以通过SqlSessionFactoryBuilder对象来构建,SqlSessionFactoryBuilder可以通过XML配置文件或一个预先定义好的Configuration实例构建出SqlSessionFactory实例。
//读取配置文件
InputStream inputStream = Resources.getResourceAsStream(“配置文件位置”);
//根据配置文件构件SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSessionFactory对象是线程安全的,它一旦被创建,在整个应用执行期间都会存在。如果多次创建同一个数据库的SqlSessionFactory,name此数据库的资源将很容易被耗尽,所以通常一个数据库只对应一个SqlSessionFactory,在构建SqlSessionFactory实例时,建议使用单例模式。
2、SqlSession
是应用程序与持久层之间执行交互操作的一个单线程对象,其主要作用是执行持久化操作。SqlSession对象包含了数据库中所有执行SQL操作的方法,其底层封装了JDBC连接,所以可以直接使用其实例来执行已映射的SQl语句。
每一个线程都应该有一个自己的SqlSession实例,并且该实例是不能被共享的。SqlSession是线程不安全的,所以适用范围最好在一次请求或一个方法中,决不能将其放在一个类的静态字段、实例字段或任何类型的管理范围(Servlet的HttpSession)中使用。使用SqlSession后要及时关闭,通常放在finally中关闭。
方法 | 说明 |
---|---|
<T>T selectOne(String statement); | 查询方法。参数statement是配置文件中定义的<select>元素的id。使用该方法后,会返回执行SQL语句查询结果的一条泛型对象。 |
<T>T selectOne(String statement, Object parameter); | 查询方法。参数statement是配置文件中定义的<select>元素的id。parameter是查询所需的参数。使用该方法后,会返回执行SQL语句查询结果的一条泛型对象。 |
<E> List<E> selectList(String statement); | 查询方法。参数参数statement是配置文件中定义的<select>元素的id。使用该方法后,会返回执行SQL语句查询结果的泛型对象的集合。 |
<E> List<E> selectList(String statement, Object parameter); | 查询方法。参数statement是配置文件中定义的<select>元素的id。parameter是查询所需的参数。使用该方法后,会返回执行SQL语句查询结果的泛型对象的集合。 |
<E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds); | 查询方法。参数statement是配置文件中定义的<select>元素的id。parameter是查询所需的参数。rowBounds是用于分页的参数对象。使用该方法后,会返回执行SQL语句查询结果的泛型对象的集合。 |
void select(String statement, Objcet parameter, ResultHandler handler); | 查询方法。参数statement是配置文件中定义的<select>元素的id。parameter是查询所需的参数。ResultHandler对象用于处理查询返回的复杂结果集,通常用于多表查询。 |
int insert(String statement); | 插入方法。参数statement是配置文件中定义的<select>元素的id。使用该方法后,会返回执行SQL语句所影响的行数。 |
int insert(String statement, Objcet parameter); | 插入方法。参数statement是配置文件中定义的<select>元素的id。parameter是插入所需的参数。使用该方法后,会返回执行SQL语句所影响的行数。 |
int update(String statement); | 更新方法。参数statement是配置文件中定义的<select>元素的id。使用该方法后,会返回执行SQL语句所影响的行数。 |
int update(String statement, Objcet parameter); | 更新方法。参数statement是配置文件中定义的<select>元素的id。parameter是更新所需的参数。使用该方法后,会返回执行SQL语句所影响的行数。 |
int delete(String statement); | 删除方法。参数statement是配置文件中定义的<select>元素的id。使用该方法后,会返回执行SQL语句所影响的行数。 |
int delete(String statement, Objcet parameter); | 删除方法。参数statement是配置文件中定义的<select>元素的id。parameter是删除所需的参数。使用该方法后,会返回执行SQL语句所影响的行数。 |
void commit(); | 提交事务的方法。 |
void rollback(); | 回滚事务的方法。 |
void close(); | 关闭SqlSession对象。 |
<T> T getMapper(Class<T> type); | 返回Mapper接口的代理对象,该对象关联了SqlSession对象,开发人员可以使用该对象直接调用方法操作数据库。参数type是Mapper的接口类型。MyBatis官方推荐通过Mapper对象访问MyBatis。 |
Connection getConnection(); | 获取JDBC数据库连接对象的方法。 |
二、主配置文件(mybatis-config.xml)
1、<properties>元素:将内部的配置外在化,通过外部配置动态替换内部定义的属性。
添加配置文件db.properties ——> 修改配置文件mybatis-config.xml
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=x5
<?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="db.properties"/>
<!--1.配置环境 ,默认的环境id为mysql-->
<environments default="mysql">
<!--1.2.配置id为mysql的数据库环境 -->
<environment id="mysql">
<!-- 使用JDBC的事务管理 -->
<transactionManager type="JDBC" />
<!--数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url"
value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!--2.配置Mapper的位置 -->
<mappers>
<mapper resource="mapper/CustomerMapper.xml" />
</mappers>
</configuration>
2、<settings>元素:用于改变MyBatis运行时行为,例如开启二级缓存、开启延迟加载等。
参数 | 描述 | 有效值 | 默认值 |
---|---|---|---|
cacheEnabled | 影响所有映射器中配置的缓存全局开关。 | true|false | false |
lazyLoadingEnabled | 延迟加载的全局开关。开启时,所有关联对象延迟加载。特定关联关系中可以通过设置fetchType属性来覆盖该项的开关状态。 | true|false | false |
aggressiveLazyLoading | 关联对象属性的延迟加载开关。开启时,对任意延迟属性的调用会使带有延迟加载属性的对象完整加载;反之每种属性都会按需加载。 | true|false | true |
multipleResultSetsEnabled | 是否允许单一语句返回多结果集(需要兼容驱动)。 | true|false | true |
useColumnLabel | 使用列标签代替列名。不同的驱动在这方面有不同的表现。具体参考驱动文档或通过测试观察所用驱动行为。 | true|false | true |
useGeneratedKeys | 允许JDBC支持自动生成主键,需要驱动兼容。如果设置为true,则这个设置强制使用自动生成主键,尽管一些驱动不兼容但仍可正常工作。 | true|false | false |
autoMappingBehavior | 指定MyBatis应如何自动映射列到字段或属性。NONE表示取消自动映射,PARIAL只会自动映射没有定义嵌套结果集映射的结果集,FULL会自动映射任意复杂的结果集。 | NONE、PARTIAL、FULL | PARTIAL |
defaultExecutorType | 默认的执行器。SIMPLE就是普通执行器,REUSE执行器会重用预处理语句(prepared statements),BATCH执行器将重用语句并执行批量更新。 | SIMPLE、REUSE、BATCH | SIMPLE |
defaultStatementTimeout | 设置超时时间,决定驱动等待数据库响应的秒数,当没有设置的时候,它取的就是驱动默认的时间。 | 任何正整数 | 没有设置 |
mapUnderscoreToCamelCase | 是否开启自动驼峰命名规则(camel case)映射。 | true|false | false |
jdbcTypeForNull | 当没有为参数提供特定的JDBC类型时,为空值指定JDBC类型。某些驱动需要指定列的JDBC类型,多数情况直接用一般类型即可,如NULL、VARCHAR、OTHER。 | NULL、VARCHAR、OTHER | OTHER |
<settings>
<setting name="cacheEnabled" value="true"/>
...
</settings>
3、<typeAliases>元素:配置文件中的Java类型设置一个别名,使用意义在于减少全限定类名的冗余。
<!--定义别名-->
<typeAliases>
<typeAlias alias="Customer" type="com.jc.pojo.Customer"/>
</typeAliases>
<!--使用自动扫描包定义别名-->
<typeAliases>
<package name="com.jc.pojo.Customer"/>
</typeAliases>
//注解定义别名
@Alias(value="user")
public class User {
...
...
}
别名 | 映射的类型 | 别名 | 映射的类型 | 别名 | 映射的类型 | 别名 | 映射的类型 | |||
---|---|---|---|---|---|---|---|---|---|---|
_byte | byte | _boolean | boolean | double | Double | map | Map | |||
_long | long | string | String | float | Float | hashmap | HashMap | |||
_short | short | byte | Byte | boolean | Boolean | list | List | |||
_int | int | long | Long | date | Date | arraylist | ArrayList | |||
_integer | int | short | Short | decimal | BigDecimal | collection | Collection | |||
_double | double | int | Integer | bigdecimal | BigDecimal | iterator | Iterator | |||
_float | float | integer | Integer | object | Objcet |
4、<typeHandler>元素:MyBatis在预处理语句(PreparedStatement)中设置一个参数或者从结果集(ResultSet)中取出一个值时,都会用其框架内部注册了的typeHandler(类型处理器)进行相关处理。typeHandler的作用就是将预处理语句中传入的参数从javaType(Java类型)转换为jdbcType(JDBC类型),或者从数据库取出结果时将jdbcType转换为javaType
类型处理器 | Java类型 | JDBC类型 |
---|---|---|
BooleanTypeHandler | java.lang.Boolean,boolean | 数据库兼容的BOOLEAN |
ByteTypeHandler | java.lang.Byte,byte | 数据库兼容的NUMERIC或BYTE |
ShortTypeHandler | java.lang.Short,short | 数据库兼容的NUMERIC或SHORT INTEGER |
IntegerTypeHandler | java.lang.Integer,int | 数据库兼容的NUMERIC或INTEGER |
LongTypeHandler | java.lang.Long,long | 数据库兼容的NUMERIC或LONG INTEGER |
FloatTypeHandler | java.lang.Float,float | 数据库兼容的NUMERIC或FLOAT |
DoubleTypeHandler | java.lang.Double,double | 数据库兼容的NUMERIC或DOUBLE |
BigDecimalTypeHandler | java.math.BigDecimal | 数据库兼容的NUMERIC或DECIMAL |
StringTypeHandler | java.lang.String | CHAR,VARCHAR |
ClobTypeHandler | java.lang.String | CLOB,LONGVARCHAR |
ByteArrayTypeHandler | byte[] | 数据库兼容的字节流类型 |
BlobTypeHandler | byte[] | BLOB,LONGVARBINARY |
DateTypeHandler | java.util.Date | TIMESTAMP |
SqlTimestampTypeHandler | java.sql.Timestamp | TIMESTAMP |
SqlDateTypeHandler | java.sql.Date | DATE |
SqlTimeTypeHandler | java.sql.Time | TIME |
<typeHandlers>
<!--以单个类形式配置-->
<typeHandler handler="com.jc.pojo.Customer"/>
</typeHandlers>
<typeHandlers>
<!--注册一个包中所有的typeHandler,系统在启动时会自动扫描包下的所有文件-->
<typeHandler handler="com.jc.pojo"/>
</typeHandlers>
5、<objectFactory>元素:MyBatis每次创建结果对象的新实例时,都会使用一个对象工厂(ObjectFactory)的实例来完成,MyBatis中默认的ObjectFactory的作用就是实例化目标类,它既可以通过默认构造方法实例化,也可以在参数映射存在的时候通过参数构造方法来实例化。MyBatis默认的ObjcetFactory是由org.apache.ibatis.reflection.factory.DefaultFactory来提供服务的。如果想覆盖ObjcetFactory的默认行为,则可以自定义ObjcetFactory实现。(不常用)
6、<plugings>元素:MyBatis允许在已映射语句执行过程中某一点进行拦截调用,这种拦截调用是通过插件来实现的。<plugings>的作用就是配置用户所开发的插件。
7、<environments>元素:对环境进行配置。即配置多重数据库。
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
...
</environments>
(1)<transactionManager>的功能是配置事务管理器,MyBatis中有两种类型:
JDBC:直接使用JDBC的提交和回滚设置,他依赖于从数据源得到的链接来管理事务的作用域
MANAGED:从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期。在默认情况下,它会关闭连接,但一些容器并不希望这样,为此可将closeConnection属性设为false来阻止它默认关闭的行为。
(2)<dataSource>:数据源配置:UNPOOLED、POOLED、JNDI
UNPOOLED:在每次请求时会打开和关闭连接。
属性 | 说明 |
---|---|
driver | JDBC驱动的Java类的完全限定名(并不是JDBC驱动中可能包含的数据源类) |
url | 数据库的URL地址 |
username | 登录数据库的用户名 |
password | 登录数据库的密码 |
defaultTransactionIsolationLevel | 默认的连接事务隔离级别 |
POOLED:利用“池”的概念将JDBC连接对象组织起来,避免了在创建新的连接实例时所需要初始化和认证的时间。这种方式使得并发Web应用可以快速地响应请求
属性 | 说明 |
---|---|
poolMaximumActiveConnections | 在任意时间可以存在的活动(也就是正在使用)连接数量,默认值:10 |
poolMaximumIdleConnections | 任意时间可能存在的空闲连接数 |
poolMaximumCheckoutTime | 在被强制返回之前,池中连接被检出(checked out)时间,默认值20000毫秒,即20秒 |
poolTimeToWait | 如果获取连接花费的时间较长,它会给连接池打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一只处于无提示的失败),默认值20000毫秒,即20秒 |
poolPingQuery | 发送到数据库的侦测查询,用于检验连接是否处在正常工作秩序中。默认是“NO PING QUERY SET”,这会导致多数数据库驱动失败时带有一定的错误消息 |
poolPingEnabled | 是否启用侦测查询。若开启,必须使用一个可执行的SQL语句设置poolPingQuery属性(最好是一个非常快的SQL),默认值:false |
poolPingConnectionsNotUsedFor | 配置poolPingQuery的使用频度,可以被设置成匹配具体的数据库连接超时时间,来避免不必要的侦测,默认值:0(表示所有连接每一时刻都被侦测,只有poolPingEnable的属性值为true时适用) |
JNDI:可以在EJB或应用服务器等容器中使用。容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的引用。
属性 | 说明 |
---|---|
initial_context | 此属性主要用于在InitialContext中寻找上下文(即InitialContext.lookup(initial_context))。此属性为可选属性,在忽略时,data_source属性会直接从InitialContext中寻找 |
data_source | 此属性表示引用数据源实例位置的上下文的路径。如果提供了initial_context配置,那么程序会在其返回的上下文中进行查找,如果没有提供,则直接在InitialContext中查找 |
8、<mappers>元素:指定MyBatis映射文件的位置。(可有多个)
<!--使用类路径引入-->
<mappers>
<mapper resource="com/jc/mapper/UserMapper.xml"/>
</mappers>
<!--使用本地文件路径引入-->
<mappers>
<mapper url="file:///D:/com/jc/mapper/UserMapper.xml"/>
</mappers>
<!--使用接口类引入-->
<mappers>
<mapper class="com.jc.mapper.UserMapper"/>
</mappers>
<!--使用包名引入-->
<mappers>
<package name="com.jc.mapper"/>
</mappers>
三、映射文件(XxxMapper.xml)
可用元素 | 属性 | 说明 |
---|---|---|
<select><insert><update><delete> | id | 表示命名空间中的唯一标识符,常与命名空间组合起来使用。组合后如果不唯一,MyBatis会抛出异常。 |
<select><insert><update><delete> | parameterType | 该属性表示传入SQL语句的参数类的全限定名或者别名。它是一个可选属性,因为MyBatis可以通过TypeHandler推断出具体传入语句的参数。其默认值是unset(依赖于驱动)。 |
<select><insert><update><delete> | flushCache | 表示调用SQL语句之后,是否需要MyBatis清空之前查询的本地缓存和二级缓存。其值为boolean类型,默认值为false。如果设置为true,则任何时候只要SQL语句被调用,都会清空本地缓存和二级缓存。 |
<select><insert><update><delete> | timeout | 用于设置超时参数,单位为秒。超时时抛出异常。 |
<select><insert><update><delete> | statementType | 用于设置MyBatis使用哪个JDBC的Statement工作,其值为STATEMENT、PREPARED(默认值)或CALLABLE,分别对应JDBC中的Statement、PreparedStatement和CallableStatement |
<select> | resultType | 从SQL语句中返回的类型的类的全限定名或者别名,如果是集合类型,那么返回的应该是集合可以包含的类型,而不是集合本身。返回时可以使用resultType或resultMap之一。 |
<select> | resultMap | 表示外部resultMap的命名引用。返回时可以使用resultType或resultMap之一。 |
<select> | useCache | 用于控制二级缓存的开启和关闭,其值为boolean类型,默认值true,表示查询结果存入二级缓存。 |
<select> | fetchSize | 获取记录的总条数设定,其默认值是unset(依赖于驱动) |
<select> | resultSetType | 表示结果集的类型,其值可设置为FORWARD_ONLY、SCROLL_SENSITIVE或SCROLL_INSENSITIVE,它的默认值是unset(依赖于驱动) |
<insert><update> | keyProperty | 此属性的作用是将插入或更新操作时的返回值赋值给PO类的某个属性,通常会设置为主键对应的属性。如果需要设置联合主键,可以在多个值之间用逗号隔开 |
<insert><update> | keyColumn | 此属性用于设置第几列是主键,当主键列不是表中的第一列时需要设置。在需要主键联合时,值可以用逗号隔开。 |
<insert><update> | useGeneratedKeys | 此属性会使MyBatis使用JDBC的getGeneratedKeys()方法来获取由数据库内部产生的主键,如MySQL和SQL Sever等自动递增的字段,其默认值为false |
1、<select>元素:映射查询语句
<select id="findById" parameterType="Integer" resultType="com.jc.pojo.Customer">
select * from customer where id = #{id}
</select>
2、<insert>元素:映射插入语句,在执行完元素中定义的SQL语句后,会返回一个表示插入记录数的整数。
<insert id="addCustomer" parameterType="com.jc.pojo.Customer" flushCache="true" statementType="PREPARED" keyProperty="" keyColumn="" useGeneratedKeys="" timeout="20">
insert into customer(username,jobs,phone) values (#{username},#{jobs},#{phone})
</insert>
<insert>与<select>属性大部分相同,如果数据库不支持主键自动增长(Oracle)或取消了主键自增,可以用如下方法实现。
<!--若表中没有记录,则id设为1,否则将id最大值+1来作为新的主键-->
<!--属性:keyProperty resultType order statementType-->
<!--order:BEFORE值时,先执行元素中的配置设置主键,然后执行插入,设置为AFTER会先执行插入语句,然后执行元素中配置-->
<insert id="insert" parameterType="com.jc.pojo.Customer">
<selectKey keyProperty="id" resultType="Integer" order="BEFORE">
select if(max(id) is null, 1, max(id) +1) as newId from customer
</selectKey>
insert into customer(id,username,jobs,phone) values (#{id}, #{username}, #{jobs}, #{phone})
</insert>
3、<update>元素和<delete>元素:映射更新和删除
<update id="updateCustomer" parameterType="com.jc.pojo.Customer">
update customer set username=#{username},jobs=#{jobs},phone=#{phone} where id=#{id}
</update>
<delete id="delCustomer" parameterType="Integer">
delete from customer where id=#{id}
</delete>
4、<sql>元素:定义代码片段,具有可重用性
<!--定义表的前缀名-->
<sql id="tablename">
${prefix}customer
</sql>
<!--定义要查询的表-->
<sql id="someinclude">
from <include refid="${include_target}"/>
</sql>
<!--定义查询列-->
<sql id="customerColumns">
id,username,jobs,phone
</sql>
<!--根据id查询客户信息-->
<select id="findCustomerById" parameterType="Integer" resultType="com.jc.pojo.Customer">
select <include refid="customerColumns"/>
<include refid="someinclude">
<property name="prefix" value="t_"/>
<property name="include_target" value="tablename"/>
</include>
where id = #{id}
</select>
5、<resultMap>元素:映射结果集,主要作用是定义映射规则、级联、的更新一集定义类型转化器等。
<resultMap id="" type="">
<constructor><!--类在实例化时,用来注入结果到构造方法中-->
<idArg/><!--ID参数;标记结果作为ID-->
<arg/><!--注入到构造方法的一个普通结果-->
</constructor>
<id/><!--用于表示哪个列是主键-->
<result/><!--注入到字段或JavaBean属性的普通结果-->
<association property=""/><!--一对一关联-->
<collection property=""/><!--一对多关联-->
<discriminator javaType=""><!--使用结果值来决定使用哪个结果映射(用于处理一个单独的数据库查询返回很多不同数据类型结果集的情况)-->
<case value=""/><!--基于某些值的结果映射-->
</discriminator>
</resultMap>
在默认情况下需要表中列名与对象属性名完全一致,然而实际开发时可能会不一致,这时候使用<resultMap>元素处理。
创建表 ——> 创建po类 ——> 创建映射文件UserMapper.xml ——> 在配置文件中引入映射文件 ——> 测试
CREATE TABLE `t_user` (
`t_id` INT(10) NOT NULL AUTO_INCREMENT,
`t_name` VARCHAR(50) NOT NULL DEFAULT '0',
`t_age` INT(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`t_id`)
)
INSERT INTO `t_user` (`t_id`, `t_name`, `t_age`) VALUES
(1, 'Lucy', 25),
(2, 'Lili', 20),
(3, 'Jim', 20);
public class User {
private Integer id;
private String name;
private Integer age;
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 getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
<?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 namespace="com.jc.pojo.User">
<resultMap id="resultMap" type="com.jc.pojo.User">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
<result property="age" column="t_age"/>
</resultMap>
<select id="findAllUser" resultMap="resultMap">
select * from t_user
</select>
</mapper>
<mappers>
<mapper resource="mapper/CustomerMapper.xml" />
<mapper resource="mapper/UserMapper.xml" />
</mappers>
@Test
public void findAllUserTest() {
List<User> list = sqlSession.selectList("com.jc.pojo.User.findAllUser");
for (User user:list) {
System.out.println(user);
}
sqlSession.close();
}