目录:
- Mybatis的核心配置 :
- 一、MyBatis的 “核心对象”
- 1.1 SqlSessionFactory
- 1.2 SqlSession :
- SqlSession对象中的操作数据库的方法 :
- \<T> T selectOne ( String statement )
- \<T> T selectOne( String statement , Object parameter )
- \<E> List\<E> selectList ( String statement )
- \<E> List\<E> selectList ( String statement , Object parameter )
- \<E> List\<E> selectList ( String statement , Object parameter , RowBounds rowBounds )
- void select ( String statement , Object parameter , ResultHandler handler )
- int insert ( String statement )
- int insert ( String statement , Object parameter )
- int update( String statement )
- int update( String statement , Object parameter)
- int delete( String statement )
- int delete( String statement , Object parameter)
- int commit( )
- void rollback( )
- void close( )
- \<T> T getMapper( Class\<T> type )
- Connection getConnection( )
- 使用工具类创建 “SqlSession” / SqlSession工具类
- 二、MyBatis的 “配置文件”
- “映射文件”中的 “主要元素”
- \<properties>元素
- \<settings>元素
- \<typeAliases>元素
- \<typeHandler>元素
- \<objectFactory>元素
- \<plugins>元素
- \<environments>元素
- \<mappers>元素
- 三、MyBatis的 “映射文件”
- “配置文件”中的 “主要元素”
- \<select>元素
- \<insert>元素
- \<update>元素和\<delete>元素
- \<sql>元素
- \<resultMap>元素 (可解决“属性名” 和 “字段名”不一样导致的数据无法映射成功的问题)
Mybatis的核心配置 :
一、MyBatis的 “核心对象”
- 在使用MyBatis框架时,主要涉及 两个核心对象 : SqlSessionFactory 和 SqlSession,它们在MyBatis框架中起着至关重要的作用。
1.1 SqlSessionFactory
SqlSessionFactory是MyBatis 框架中十分重要的对象,它是单个数据库映射关系经过编泽后的内存镜像,其主要作用是 创建SqlSession。
SqlSessionFactory 对象的实例可以通过 SqlSessionFactoryBuilder对象 来构建,而SqlSessionFactoryBuilder对象 则可以通过 XML配置文件 或一个预先定义好的 Configuration实例 构建出SqlSessionFactory的实例。
以下内容讲解的是 :就是 通过XML配置文件 构建出的SqlSessionFactory实例,其实现代码如下:
InputStream inputStream = Resources.getResourceAsStream("配置文件的位置"); //通过SqlSessionFactoryBuilder的 build()方法 + 配置文件来创建 SqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSessionFactory对象 是 线程安全 的,它一旦被创建,在整个应用执行期间都会存在。如果我们多次地创建同一个数据库的SqlSessionFactory,那么此数据库的资源将很容易被耗尽。为了解决此问题,通常每一个数据库都会只对应一个 SqlSessionFactory, 所以在 构建SqlSessionFactory实例时,建议使用单列模式。
1.2 SqlSession :
SqlSession 是MyBatis 框架中另一个重要的对象, 它是 应用程序 与 持久层之间执行与操作的一个单线程对象,其主要作用是 执行持久化操作。
SqlSession对象包含数据库中所有执行SOL操作的方法 (SqlSession中有很多操作数据库的方法),由于其底层封装了JDBC连接,所以可以直接使用SqlSession实例来 执行已映射的SQL语句
(可用SqlSession来执行 “映射文件” 中的sql语句)。
每一个线程都应该有一个自己的SqlSession实例,并且该实例是不能被共享的。同时,SqlSession实例 是 线程不安全 的,因此 其使用范围 最好在 一次请求或一个方法 中,绝不能将其放在一个类的静态字段、实例字段 或 任何类型的管理范围 (如Servlet的HttpSession)中使用。
使用完SqlSession对象之后,要及时地关闭它,通常可以将其放在fnally块中关闭。
//通过 sqlSessionFactory对象获得"SqlSession" SqlSession sqlSession = sqlSessionFactory.openSession(); try{ //此处执行持久化操作 }finally{ sqlSession.close(); }
SqlSession对象中的操作数据库的方法 :
<T> T selectOne ( String statement )
<T> T selectOne ( String statement ) : 查询方法 : 参数 statement 是在 “ 映射文件” 中定义的 <select>元素 的 id 。
目的是 : 获得映射文件中的 “<select>元素下所代表的 sql语句 作为selectOne( )方法的参数 ”)。使用该方法后,会返回执行SQL语句查询结果的 一条泛型对象。
<T> T selectOne( String statement , Object parameter )
<T> T selectOne ( String statement, Object parameter ) :查询方法 : 参数 statement 是在 “ 映射文件” 中定义的 <select>元素 的 id 。 parameter是查询所需的 参数。使用该方法后,会返回执行SQL语句查询结果的 一条泛型对象。
<E> List<E> selectList ( String statement )
<E> List<E> selectList ( String statement ) : 查询方法 : 参数 statement 是在 “映射文件” 中定义的 <select>元素 的 id 。使用该方法后,会返回执行SQL语句查询结果的 泛型对象的集合。
<E> List<E> selectList ( String statement , Object parameter )
<E> List<E> selectList ( String statement , Object parameter ) : 查询方法 : 参数 statement 是在 “ 映射文件” 中定义的 <select>元素 的 id , parameter 是查询所需的参数。使用该方法后,会返回执行SQL语句查询结果的 泛型对象的集合。
<E> List<E> selectList ( String statement , Object parameter , RowBounds rowBounds )
<E> List<E> selectList ( String statement , Object parameter ) : 查询方法 : 参数==statement==是在 “ 映射文件” 中定义的 <select>元素 的 id , parameter 是查询所需的参数,rowBounds是用于分页的参数对象。使用该方法后会返回执行SQL语句查询结果的 泛型对象的集合。
void select ( String statement , Object parameter , ResultHandler handler )
void select ( String statement, Object parameter,ResultHandler handler ) : 查询方法 : 参数statement是在配置文件中定义的 <select>元素的id,parameter 是查询所需的 参数, ResultHandler对象用于处理查询返回的复杂结果集。 (通常用于多表查询)
int insert ( String statement )
int insert ( String statement ) : 插入方法 : 参数 statement是在 “映射文件” 中定义的 <select>元素 的 id ,使用该方法后,会返回执行 SQL语句所影响的行数。
int insert ( String statement , Object parameter )
int insert ( String statement , Object parameter ) : 插入方法 : 参数 statement 是在 “ 映射文件” 中定义的 <select>元素 的 id ,parameter 是查询所需的参数。使用该方法后,会返回执行 SQL语句所影响的行数。
int update( String statement )
int update ( String statement ) : 更新方法 : 参数 statement 是在 “ 映射文件” 中定义的 <update>元素 的 id ,使用该方法后,会返回执行 SQL语句所影响的行数。
int update( String statement , Object parameter)
int update ( String statement , Object parameter ) : 更新方法 : 参数 statement 是在 “ 映射文件” 中定义的 <update>元素 的 id ,parameter 是更新所需的参数。使用该方法后,会返回执行 SQL语句所影响的行数。
int delete( String statement )
int delete ( String statement ) : 删除方法 : 参数 statement 是在 “映射文件” 中定义的 <delete>元素 的 id ,使用该方法后,会返回执行 SQL语句所影响的行数。
int delete( String statement , Object parameter)
int delete ( String statement , Object parameter ) : 删除方法 : 参数 statement 是在 “ 映射文件” 中定义的 <delete>元素 的 id ,parameter 是删除所需的参数使用该方法后,会返回执行 SQL语句所影响的行数。
int commit( )
int commit ( ) : 提交事务 的方法。
void rollback( )
int rollback ( ) : 回滚事务 的方法。
void close( )
int close ( ) : 关闭SqlSession 对象。
<T> T getMapper( Class<T> type )
- <T> T getMapper ( Class<T> type ) : 该方法会返回 Mapper接口 的 代理对象,该对象关联了SqlSession对象,开发人员可以使用该对象直接调用方法操作数据库。参数type是Mapper的接口类型。MyBatis官方推荐通过
Mapper对象访问MyBatis。- 该方法 : getMapper( ) 的目的是根据传入的 类类型 :
type
返回一个与该类型匹配的对象。具体实现可能涉及反射机制,用于 创建并返回一个与传入类类型相匹配的实例。
Connection getConnection( )
Connection getConnection( ) : 获取 JDBC数据库连接对象 的方法。
使用工具类创建 “SqlSession” / SqlSession工具类
使用工具类创建 “SqlSession”对象 :
package com.myh.utils; 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 java.io.IOException; import java.io.InputStream; /** * 工具类 */ public class SqlSessionUtils { //获得SqlSession的"工具类" private static SqlSessionFactory sqlSessionFactory = null; //初始化 SqlSessionFactory 对象 static { //静态代码块 try { //使用Mybatis提供的Resources类加载mybatis-config.xml配置文件 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); //构建SqlSessionFactory工厂 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } /** * 获得SqlSession对象的静态方法 */ public static SqlSession getSession() { return sqlSessionFactory.openSession(); } }
这样,我们在使用时就 只创建了一个SqlSessionFactory 对象,并且可以通过工具类的 getSession( ) 方法, 来 获取SqlSession对象。
二、MyBatis的 “配置文件”
MyBatis的核心配置文件中,包含了很多影响MyBatis行为的重要信息。这些信息通常在一个项目中只会在一个配置文件中编写,并且编写后也不会轻易改动。
“映射文件”中的 “主要元素”
在 MyBatis 框架的 核心配置文件 (即 mybatis-config.xml )中,<configuration> 元素 是配置文件的 根元素,其他元素都要在 <configuration> 元素内配置。
Mybatis配置文件中 主要元素图 :(要熟悉 <configuration>元素各个子元素的配置。)
ps :
==<Cofgnaion>的子元素必须按照图中由上到下==的顺序进行配置,否则Mybatis在解新xml配置文件的时候会报错。
<properties>元素
- <properties>是一个配置属性的元素,该元素通常用于将内部的配置 “外在化”,即通过外部的配置来动态地替换内部定义的属性
(直接的使用 : 将外部的 Xxx.properties文件中的属性用于 mybatis配置文件中 )。
例如,数据库的连接等属性,就可以通过典型的 Java属性文件 ( .properties文件 )中的配置来替换。ps :
当我们在mybatis配置文件中 使用 <properties>元素导入 .properties文件时,即可在mybatis配置文件中,即直接使用 .properties文件中的数据 。db.properties
jdbc.driver = com.mysql.jdbc.Driver jdbc.url = jdbc:mysql://localhost:3306/mybatis jdbc.username = root jdbc.password = root
mybatis-config.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属性 --> <!-- 通过properties属性引入 .properties配置文件, mybatis配置文件中则可直接使用 .properties中的数据,进行"动态替换" --> <properties resource="db.properties"/> <!-- environments属性 --> <environments default="mysql"> <environment id="mysql"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <!-- 通过“properties属性”来将 以下的driver、url、username、password 和 .properties配置文件 中的数据进行“动态替换” --> <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> </configuration>
完成上述配置后,dataSource中连接数据库的4个属性 ( driver、url、usermame和password值将会由db.properties文件中对应的值来动态替换。这样就为配置提供了诸多灵活的选择。
除了可以像上述通过外部配置文件来定义属性值外,还可以通过配置 <properties>元素的子元素 <property>,以及通过方法参数传递的方式来获取属性值。由于使用properties配置文件来配置属性值可以方便地在多个配置文件中使用这些属性值,并且方便日后的维护和修改,所以在实际开发中,使用.properties文件来配置属性值是最常用的方式。
<settings>元素
<settings>元素主要用于改变MyBatis运行时的行为,例如 开启二级缓存、开启延迟加载 等。
虽然不配置<settings>元素,也可以正常运行MyBatis, 但是熟悉<settings>的配置内容以及它们的作用还是十分必要的。常见的**<settings>属性配置在 “配置文件” 中的使用** :
<settings> <setting name="cacheEnabled" value="true" /> <setting name="lazyLoadingEnabled" value="true" /> <setting name="multipleResultSetsEnabled" value="true"/> <setting name="useColumnLabel" value="true"/> <setting name="useGeneratedKeys" value="false" /> <setting name="autoMappingBehavior" value="PARTIAL"/> ..... </settings>
<typeAliases>元素
<typeAliases>元素 用于为配置文件中的Java类型设置一个简短的名字,即 设置别名。别名的设置与XML配置相关,其使用的意义在于减少全限定类名的冗余。 如 : 可用 <typeAliases>元素 为POJO类设置一个 “别名”。
<?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> <!-- 定义别名 --> <typeAliases> <!-- typeAlias元素 为 typeAliases元素的 "子元素" --> <typeAlias alias="user" type="com.myh.po.Customer"/> </typeAliases> </configuration>
上述示例中,<typeAliases> 元素的子元素 <typeAlias> 中的type属性用于指定需要被定义别名的类的全限定名; alias属性的属性值user 就是自定义的别名,它可以代替com.myh.po.Customer使用在MyBatis文件的任何位置。如果省略alias属性,MyBatis 会默认将类名首字母 小写后的名称作为别名。
当POJO类过多时,还可以通过自动扫描包 的 形式自定义别名 (此时以类名首字母小写后的名称为 “别名”),具体示例如下 :
<?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> <!-- 定义别名 --> <typeAliases> <!-- 使用自动扫描包来定义“别名” --> <!-- Mybatis会将所用 com.myh.po包中POJO类以首字母小写的名称 作为“别名” --> <!-- 如: Customer 的 默认设置的别名为: customer --> <package name="com.myh.po"/> </typeAliases> </configuration>
需要注意的是,上述方式的别名只适用于没有使用注解的情况。如果在程序中使用了注解,则别名为其注解的值, 具体如下 :
//使用注解来为该POJO类设置在 mybatis-config.xml配置文件中使用的 "别名" @Alias(value = "customer") public class Customer { ..... }
除了可以使用 <typeAliases>元素自定义别名外,MyBatis框架还默认为许多常见的Java类型(如数值、 字符串、日期和集合等 )提供了 相应的类型别名。(可使用时查询常见的Java类型的别名是什么)
<typeHandler>元素
MyBatis在 预处理语句( PreparedStatement )中 设置一个参数或者从结果集 ( ResultSet )中取出一个值 时,都会用其框架内部注册了的 typeHandler ( 类型处理器 ) 进行相关处理。
typeHandler的作用就是将预处理语句 中传入的参数从 javaType ( Java类型) 转换为 jdbcType
( JDBC类型),或者从数据库取出结果时将 jdbcType 转换为 javaType。为了方便转换,Mybatis框架提供了一系列默认的类型处理器。
类型处理器 Java 类型 JDBC 类型 BooleanTypeHandler java.lang.Boolean, boolean 数据库兼容的 BOOLEAN ByteTypeHandler java.lang.Byte, byte 数据库兼容的 NUMERIC 或 BYTE ShortTypeHandler java.lang.Short, short 数据库兼容的 NUMERIC 或 SMALLINT IntegerTypeHandler java.lang.Integer, int 数据库兼容的 NUMERIC 或 INTEGER LongTypeHandler java.lang.Long, long 数据库兼容的 NUMERIC 或 BIGINT 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 ClobReaderTypeHandler java.io.Reader - ClobTypeHandler java.lang.String CLOB, LONGVARCHAR NStringTypeHandler java.lang.String NVARCHAR, NCHAR NClobTypeHandler java.lang.String NCLOB BlobInputStreamTypeHandler java.io.InputStream - ByteArrayTypeHandler byte[] 数据库兼容的字节流类型 BlobTypeHandler byte[] BLOB, LONGVARBINARY DateTypeHandler java.util.Date TIMESTAMP DateOnlyTypeHandler java.util.Date DATE TimeOnlyTypeHandler java.util.Date TIME SqlTimestampTypeHandler java.sql.Timestamp TIMESTAMP SqlDateTypeHandler java.sql.Date DATE SqlTimeTypeHandler java.sql.Time TIME ObjectTypeHandler Any OTHER 或未指定类型 EnumTypeHandler Enumeration Type VARCHAR 或任何兼容的字符串类型,用来存储枚举的名称(而不是索引序数值) EnumOrdinalTypeHandler Enumeration Type 任何兼容的 NUMERIC 或 DOUBLE 类型,用来存储枚举的序数值(而不是名称)。 SqlxmlTypeHandler java.lang.String SQLXML InstantTypeHandler java.time.Instant TIMESTAMP LocalDateTimeTypeHandler java.time.LocalDateTime TIMESTAMP LocalDateTypeHandler java.time.LocalDate DATE LocalTimeTypeHandler java.time.LocalTime TIME OffsetDateTimeTypeHandler java.time.OffsetDateTime TIMESTAMP OffsetTimeTypeHandler java.time.OffsetTime TIME ZonedDateTimeTypeHandler java.time.ZonedDateTime TIMESTAMP YearTypeHandler java.time.Year INTEGER MonthTypeHandler java.time.Month INTEGER YearMonthTypeHandler java.time.YearMonth VARCHAR 或 LONGVARCHAR JapaneseDateTypeHandler java.time.chrono.JapaneseDate DATE 当MyBatis框架所提供的 这些类型处理器不能够满足需求时,还可以通过自定义的方式对类型处理器进行扩展 ( 自定义类型处理器可以通过实现TypeHandler 接口 或者 继承 BaseTypeHandle类来定义)。
<typeHandler> 元素就是用于在配置文件中注册自定义的类型处理器的。它的使用方式有两种 :
① 注册一个类的类型处理器
②注册一个包中所有的类型处理器CustomertypeHandler.java
package com.myh.type; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.TypeHandler; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class CustomertypeHandler implements TypeHandler { @Override public void setParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException { } @Override public Object getResult(ResultSet rs, String columnName) throws SQLException { return null; } @Override public Object getResult(ResultSet rs, int columnIndex) throws SQLException { return null; } @Override public Object getResult(CallableStatement cs, int columnIndex) throws SQLException { return null; } }
mybatis-config.xml
<!-- 注册一个类的类型处理器 --> <typeHandlers> <!-- 以单个类的形式配置 --> <typeHandler handler="com.myh.type.CustomertypeHandler"/> </typeHandlers> <!-- 注册一个包中所有类的类型处理器 --> <typeHandlers> <!-- 注册一个包中所有的typeHandler,系统在启动时会自动扫描包下的所有文件 --> <package name="com.myh.type"/> </typeHandlers>
<objectFactory>元素
MyBatis框架每次创建 结果对象的新实例 时,都会使用一个对象工厂( ObjectFactory )的实例来完成。MyBatis中默认的 ObjectFactory的作用 就是 实例化目标类,它既可以通过默认构造方法实例化,也可以在参数映射存在的时候通过参数构造方法来实例化。
在通常情况下, 我们使用默认的ObjectFactory即可,MyBatis 中默认的ObjectFactory是由org.apache.ibatis rflection.factory.DefaultObjectFactory来提供服务的。大部分场景下都不用配置和修改,但如果想覆盖ObjectFactory的默认行为,则可以通过自定义ObjectFactory来实现。
MyObjectFactory.java
package com.myh.objFactory; import org.apache.ibatis.reflection.factory.DefaultObjectFactory; import java.util.List; import java.util.Properties; //自定义工厂类 : 该类可以实现ObjectFactory接口 或 继承 DefaultObjectFactory类 public class MyObjectFactory extends DefaultObjectFactory { //要继承DefaultObjectFactory类 private static final long serialVerSionUID = -4114845625429965832L; @Override public <T> T create(Class<T> type) { return super.create(type); } @Override public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) { return super.create(type, constructorArgTypes, constructorArgs); } @Override public void setProperties(Properties properties) { super.setProperties(properties); } @Override public <T> boolean isCollection(Class<T> type) { return super.isCollection(type); } }
mybatis-config.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> <objectFactory type="com.myh.objFactory.MyObjectFactory"> <property name="name" value="MyObjectFactory"/> </objectFactory> </configuration>
<plugins>元素
- MyBatis允许在已映射语句执行过程中的某一点进行拦截调用,这种拦截调用是通过插件来实现的。<plugins> 元素的作用就是配置用户所开发的插件。如果用户想要进行插件开发,必须要先了解其内部运行原理,因为在试图修改或重写已有方法的行为时,很可能会破坏MyBatis原 有的核心模块。
<environments>元素
在配置文件中,<environments>元素用于对环境进行配置。MyBatis的 环境配置 实际上就是 数据源的配置,我们可以通过 <environments>元素配置多种数据源,即配置多种数据库。
<!-- environments属性 --> <environments default="mysql"> <environment id="mysql"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <!-- 通过“properties属性”来将 以下的driver、url、username、password 和 .properties配置文件 中的数据进行“动态替换” --> <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>
在上述代码中,<environments>元素是环境配置的 根元素,它包含个一default属性,该属性用于指定默认的环境ID。 是 <environments>元素的 “子元素”,它 : <environment> 可以定义多个,其记属性用于表示所定义环境的ID值。在 environment元素内,包含事务管理 ( transactionManager ) 和 数据源 ( dataSource ) 的配置信息,其 <transactionManager>元素用于配置事务管理,它的type属性用于指定事务管理的方式,即使用哪种事务管理器;<dalaSource>元素用于配置数据源,它的type属性用于指定使用哪种数据源。
在MyBatis中,可以配置两种类型的事务管理器,分别是 JDBC 和 MANAGED。JDBC : 此配置直接使用了JDBC的提交和回滚设置,它依赖于从数据源得到的连接来管理事务的作用域。
MANAGED : 此配置从来不提交或回滚一个连接 ,而是让容器来管理事务的整个生命周期。
在默认情况下,它会关闭连接,但一些容器并不希望这样,为此可以将closeConnection属性设
置为false来阻止它默认的关闭行为。ps :
如果没有必要中 使用的是 Spring+ MyBatis,则 没有必要 在MyBatis ( mybatis-config.xml ) 中 配置事务管理器,因为实际开发中,会使用Spring自带的管理器来实现事务管理。
<mappers>元素
在配置文件 ( mybatis-config.xml )中,<mappers>元素 用于 指定MyBatis 映射文件 (引入“映射文件”)(XxxMapper.xml )的 位置,一般可以使用以下 4种方法 引入映射文件。 ( 一个mybatis-config.xml 配置文件可以引入多个“映射文件”。)
① 使用 “类路径” 引入
② 使用 “本地文件路径” 引入
③ 使用 “接口类” 引入
④ 使用 “包名” 引入① 使用 “类路径” 引入
<mappers> <!-- 使用"类路径"读取"映射文件" --> <mapper resource="com/myh/mapper/CustomerMapper.xml"/> </mappers>
② 使用 “本地文件路径” 引入
<mappers> <!-- 使用“本地文件路径”引入“映射文件” --> <mapper url="file:///D:/com/myh/mapper/CustomerMapper.xml"/> </mappers>
③ 使用 “接口类” 引入
<mappers> <!-- 使用“接口类”引入“映射文件” --> <mapper class="com.myh.mapper.CustomerMapper"/> </mappers>
④ 使用 “包名” 引入
<mappers> <!-- 使用“包名”引入“映射文件” --> <package name="com.myh.mapper"/> </mappers>
三、MyBatis的 “映射文件”
- 映射文件 ( XxxMapper.xml )是Mybatis框架中十分重要的文件,可以说,Mybatis框架的强大之处就体现在“映射文件”的编写上。
- 在映射文件中,<mapper>元素 是映射文件的根元素,其他元素都是它的子元素。
“配置文件”中的 “主要元素”
<select>元素
<select>元素 用于映射 “查询语句”,它可以帮助我们从数据库中读出数据,并组装数据给企业开发者。
<!-- “查询数据”--> <select id="findCustomerById" parameterType="Integer" resultType="com.myh.po.Customer"> select * from t_customer where id = #{id} </select>
上述语句中的唯一标识为 findCustomerByld,它接收一个 Integer 类型的参数,并返回一个Customer类型的对象。
<select>元素中,除了上述代码中的几个属性外,还有其他一些可以配置的属性,如下所示 :
属性 说明 id 表示命名空间中的唯一标识符, 常与命名空间组合起来使用。组合后如果不唯一, MyBatis会抛出异常。 parameterType 该属性表示传入SQL语句的参数类的全限定名或者别名。它是一个可选属性, 因为MyBatis可以通过TypeHandler推断出具体传入语句的参数。其默认值是unset (依赖于驱动)。 resultType 从SQL语句中返回的类型的类的全限定名或者别名。如果是集合类型,那么返回的应该是集合可以包含的类型,而不是集合本身。返回时可以使用resultType或resultMap之一。 resultMap 表示外部resultMap的命名引用。返回时可以使用resultType或resultMap之一。 flushCache 表示在调用SQL语句之后,是否需要MyBatis清空之前查询的本地缓存和二级缓存。其值为布尔类型( truelfalse),默认值为false。如果设置为true,则任何时候只要SQL语句被调用,都会清空本地缓存和二级缓存。 useCache 用于控制二级缓存的开启和关闭。其值为布尔类型( truelfalse),默认值为true,表示将查询结果存入二级缓存中。 timeout 用于设置超时参数,单位为秒。超时将抛出异常。 fetchSize 获取记录的总条数设定,其默认值是unset (依赖于驱动)。 statementType 用于设置MyBatis使用哪个JDBC的Statement工作,其值为STATEMENT、PREPARED(默认值) 或CALLABLE, 分别对应JDBC中的Statement 、PreparedStatement 和 CallableStatement。
属性 说明 resultSetType 表示结果集的类型,其值可设置为FORWARD_ONLY、SCROLL_SENSITIVE 或SCROLL_INSENSITIVE, 它的默认值是unset (依赖于驱动)。
<insert>元素
- <insert>元素用于映射“插入语句”,在执行完元素中定义的SQL语句后,会返回一个表示插入记录数的整数。
<!-- useGeneratedKeys="true" : 获得该insert语句插入数据库时形成的“主键id” / 获得数据库内部产生的主键id keyProperty="id" : 将插入或更新时的“返回值”赋值到PO类的对应的“属性”上 : 即将刚获得的“主键id”赋值到PO类对应的id属性上 --> <!-- 该insert语句的返回值 : ①返回插入成功的行数 ②插入行的主键id --> <insert id="addCustomer" parameterType="com.myh.po.Customer" flushCache="true" statementType="PREPARED" keyProperty="id" keyColumn="" useGeneratedKeys="true" timeout="20"> insert into t_customer(username,jobs,phone) values(#{username},#{jobs},#{phone}) </insert>
以上的 insert语句的返回值 : ①返回插入成功的行数 ②插入行的主键id。
从上述代码中可以看出,<insert>元素的属性 与 <select>元素 的 属性大部分相同,<insert>元素包含了 3个特有属性。
- <insert>元素 中的三个特有 属性 :
属性 说明 keyProperty ( 仅对insert和update有用 )此属性 ( keyProperty )的作用是将插入 或 更新操作时的返回值赋值给 PO类的某个属性,通常会设置为“主键”对应的属性。
(通常会设置该属性的值为“id” (即将插入形成的“主键id”值赋值到PO类中 )。如果需要设置联合主键,可以在多个值之间用逗号隔开。
例子如 :
keyProperty =“i‘d” ( 要结合useGeneratedKeys属性使用 ) :
将useGeneratedKeys属性获得的 ( 插入形成的 ) “主键id” 赋值到PO类的对应的id属性上,这样就能获得insert语句生成的数据对应的“主键id”了。keyColumn ( 仅对insert和update有用 ) 此属性用于 设置第几列是主键,当主键列不是表中的第一列时需要设置,在需要主键联合时,值可以使用逗号隔开。 useGeneratedKeys ( 仅对insert和update有用 )此属性会使 MyBatis 使用 JDBC 的 getGeneratedKeys( )方法来获取由数据库内部生产的 主键 (此时一般配合keyProperty属性使用来将该“主键 赋值给PO类对应的属性上。”), 如MySQL和SQL Server等自动递增的字段,其 默认值为false。 执行插入操作后,很多时候我们会需要返回插入成功的数据生成的主键值 ( 表中主键id ),此时就可以通过
上面所讲解的3个属性来实现。
- 如果使用的数据库支持主键自动增长 (如MySQL ),那么可以通过keyProperty属性 指定PO类的某个属性接收主键返回值 ( 通常会设置到id属性上 : 将主键id赋值给PO类的 id属性上 ),同时还要通过 useGeneratedKeys属性才能实现目标功能。 例子如下 :
<insert>元素 中的三个特有 属性 例子如 :
CustomerMapper.xml (映射文件) :
<!-- useGeneratedKeys="true" : 获得该insert语句插入数据库时形成的“主键id” / 获得数据库内部产生的主键id keyProperty="id" : 将插入或更新时的“返回值”赋值到PO类的对应的“属性”上 : 即将刚获得的“主键id”赋值到PO类对应的id属性上 --> <!-- 该insert语句的返回值 : ①返回插入成功的行数 ②插入行的主键id --> <insert id="addCustomer" parameterType="com.myh.po.Customer" keyProperty="id" useGeneratedKeys="true" > insert into t_customer(username,jobs,phone) values(#{username},#{jobs},#{phone}) </insert>
以上的 insert语句的返回值 : ①返回插入成功的行数 ②插入行的主键id。
CustomerTest.java (测试类) :
public class CustomerTest { @org.junit.Test //单元测试 public void addCustomerTest() throws IOException { //1.读取mybatis框架的配置文件 String resource = "com/myh/映射文件的元素/mybatis-config.xml"; //通过“输入流”读取mybatis配置文件 /* 在该mybatis-config.xml配置文件中,已配置了“数据源”信息 和配置了"映射文件 : XxxMapper.xml”的位置, 可实施加载“映射文件” */ InputStream inputStream = Resources.getResourceAsStream(resource); //2.根据配置文件“构建会话工厂 : SqlSessionFactory ” SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //3.通过SqlSessionFactory(会话工厂)创建SqlSession("会话"对象) SqlSession sqlSession = sqlSessionFactory.openSession(); Customer customer = new Customer(); customer.setUsername("小蓝"); customer.setJobs("学生"); customer.setPhone("12345678"); //将该Customer对象存入到数据库中,同时目的是: 将存入到数据库中的数据对应的“主键id”获得且返回 int insert = sqlSession.insert("CustomerMapper.addCustomer", customer); /** * 输出"插入数据"形成的"主键id值" (从数据库中获得的主键id值是存储在Customer这个PO类中的) */ System.out.println(customer.getId()); if (insert > 0) { System.out.println("你成功插入了" + insert + "条数据!"); } else { System.out.println("插入数据操作失败! "); } //4.设置“事务管理” sqlSession.commit(); //5.关闭SqlSession sqlSession.close(); } }
通过上述的<insert>元素的三个特有属性,即可获得插入数据的对应的 “ 主键id”。
如果使用的数据库不支持主键自动增长 (如Oracle ), 或者支持增长的数据库 取消了主键自增 的规则时,也可以使用MyBatis提供的另一种方式来自定义生成主键。 例子如下 :
<?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"> <!-- 映射文件中,插入数据用 <insert>元素 --> <!-- #{} : 相当于"占位符" ${} : 相当于在sql语句后要拼接的"字符串" --> <mapper namespace="CustomerMapper"> <insert id="insertCustomer" parameterType="com.myh.po.Customer"> <selectKey keyProperty="id" resultType="Integer" order="BEFORE"> select if(max(id) is null,1,max(id) + 1)as newId from t_customer </selectKey> insert into t_customer(username,jobs,phone) values(#{username},#{jobs},#{phone}) </insert> </mapper>
上述代码中,<selectKey> 元素会首先运行,它会通过自定义的语句来设置数据中的主键 (如果
t_customer表中没有记录,则将id设置为1,否则就将id的最大值加1,来为新的主键),然后再调用插入语句。
<selectKey>元素在使用时可以设置以下几种属性 :<selectKey keyProperty="id" resultType="Integer" order="BEFORE" statementType="PREPARED">
在上述 <selectKey>元素的几个属性中,keyProperty、 resultType 和statementType的作用与前面讲解的相同,order 属性可以被设置为BEFORE或AFTER。如果设置为BEFORE,那么它会首先执行 <selectKey>元素中的配置来设置主键,然后执行插入语句;如果设置为AFTER,那么它会先执行插入语句,然后执行 <selectKey>元素中的配置内容。
<update>元素和<delete>元素
- <update> 和 <delete>元素 的使用比较简单,它们的属性配置也基本相同 ,其常用属性如下 :
<!-- 更新 --> <update id="updateCustomer" parameterType="com.myh.po.Customer" flushCache="true" statementType="PREPARED" timeout="20"> </update> <!-- 删除 --> <delete id="deleteCustomer" parameterType="com.myh.po.Customer" flushCache="true" statementType="PREPARED" timeout="20"> </delete>
从上述配置代码中可以看出,<update>和<delete>元素的属性基本与 <select>元素中的属性一致。
与 <insert>元素一样,<update> 和<delete>元素在执行完之后,也会返回一个表示影响记录条数的整数,其使用示例如下 :<!-- 更新 --> <update id="updateCustomer" parameterType="com.myh.po.Customer"> update t_customer set username = #{username},jobs=#{jobs},phone=#{phone} where id = #{id} </update> <!-- 删除 --> <delete id="deleteCustomer" parameterType="Integer"> delete from t_customer where id = #{id} </delete>
<sql>元素
在一个映射文件中,通常需要定义多条SQL语句,这些SQL语句的组成可能有一部分是相同的 ( 如多条select语句中都查询相同的id、username、 jobs 字段),如果每一个SQL语句都重写遍相同的部分, 势必会增加代码量,导致映射文件过于臃肿。
那么有没有什么办法将这些SQL语句中相同的组成部分抽取出来,然后在需要的地方引用呢 ?
答案是肯定的,我们可以在映射文件中使用MyBatis所提供的 <sql>元素来解决上述问题。<sql>元素的作用 : 就是定义可重用的SQL代码片段,然后在其他语句中引用这一代码片段。例子如 :
<sql id="customerColumns"> id,username,jobs,phone</sql> <select id="findCustomerById" parameterType="Integer" resultType="com.myh.po.Customer"> select <include refid="customerColumns"/> from t_customer where id = #{id} </select>
<resultMap>元素 (可解决“属性名” 和 “字段名”不一样导致的数据无法映射成功的问题)
<resultMap>元素表示结果映射集,是 MyBatis中最重要 也是 最强大 的元素。它的主要作用 : 是
定义映射规则、级联的更新 以及 定义类型转化器 等。ps :
<resultMap>元素 可解决“属性名” 和 “字段名” 不一样导致的数据无法映射成功的问题。<resutMap>元素中包含了属性 / 子元素,如下所示 :
<!-- resultMap的元素结构 --> <resultMap type="" id=""> <constructor> <!-- 类在实例时,用来注入"结果"到"结构方法"中 --> <idArg/> <!-- ID参数;标记结果为ID --> <arg/> <!-- 注入到构造方法的一个普通结果 --> </constructor> <id/> <!-- 用于表示哪个"列"是"主键" --> <result/> <!-- 注入到“字段”或“JavaBean属性”的普通结果 --> <association property=""/> <!-- 用于一对一关联 --> <collection property=""/> <!-- 用于一对多关联 --> <discriminator javaType=""> <!-- 使用"结果值"来决定哪个"结果映射"--> <case value=""></case> </discriminator> </resultMap>
<resutMap>元素 的 属性 关系如下表所示 :
属性 描述 type 表示需要 映射 的POJO ( 普通Java对象 ) id 这个 resultMap 的 唯一标识。 <resutMap>元素 的 子元素 关系如下表所示 :
子元素 描述 <constructor> 用于配置构造方法 ( 当一个POJO中未定义无参的构造方法时,就可以使用 <constructor>元素 进行配置)。 <id> 分别标记 POJO中属性中的“主键”和 标记数据库表中字段的 “主键”,并 将二者进行关联。
ps :
这意味着,通过 <resultMap> 中的 <id>元素的配置,POJO 中 “主键”属性名 不用 和数据库中 “主键”名相同。<result> 表示 POJO 中 “属性”和 数据库表中列 的 映射关系。(用于将 POJO中 “属性”和 数据库表中的 “列”进行关联。 )
ps :
这意味着,通过 <resultMap> 中的 <result>元素的配置,数据库中的 “字段” 以及 该“字段”相对应的 “属性”名,不用一致。(在 <result>中设置各自的名称即可)<association> 表示“一对一”关联。用于处理“多表”时的关联关系。 <collection> 表示“一对多”关联。用于处理“多表”时的关联关系。 <discriminator> 使用"结果值"来决定哪个"结果映射"。用于处理一个单独的数据库查询 返回很多不同数据类型 结果集的情况。 在默认情况下,MyBatis程序在运行时会 自动地将查询到的数据与需要返回的对象的属性进行匹配赋值 ( 需要表中的 列名与对象的属性名称完全一致 )。 然而实际开发时,数据表中的列和需要返回的对象的属性可能不会完全一致, 这种情况下MyBatis是不会自动赋值的。此时,就可以使用 <resultMap>元素进行处理。
实际开发中,如果当POJO中“属性名” 和 数据库中“字段名” 不一致,此时查询数据库,数据会无法映射到POJO类中,最后导致查询到的内容为 : null。 此时用 <resultMap>元素即可解决这个问题。
例子如:
此时可使用“映射文件” 中的因属性名 和 字段名不一致而导致的数据无法映射到POJO中的问题。如下所示 :
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元素中使用resultType时,当数据库中"字段名" 和POJO中"属性名"不一致时,select的数据将则无法映射到POJO类中,即输出内容为null --> <!-- select元素中用resultMap时,数据库中“字段名” 和 POJO中“属性名”不用保持一致,此时也能完成将select到的数据映射到POJO类中--> <select id="selectUser_resultType" resultType="com.myh.po.User" parameterType="Integer"> select * from t_user where t_id = #{id} </select> <!-- 上面这个select的查询的数据是无法映射到POJO类中,即select的数据为null,因为数据库中“字段名” 和 POJO中的“属性名”, 此时可用 <resultMap>元素来解决这个问题 --> <resultMap id="resultMap" type="com.myh.po.User"> <!-- 下面配置的目的 : "属性名" 和 "字段名" 可以不用保持一致 --> <id property="id" column="t_id"/> <result property="name" column="t_name"/> <result property="age" column="t_age"/> </resultMap> <!-- 因为此处用了resultMap(已经配置好了,完成各种内容的“映射了”,所以即使"属性名" 和 “字段名”不一致,也能select到数据) --> <select id="selectUser_resultMap" resultMap="resultMap" parameterType="Integer"> select * from t_user where t_id = #{id} </select> </mapper>
UserTest.java (测试类)
public class UserTest { @org.junit.Test //单元测试 public void selectUser_resultType_resultMap_Test() throws IOException { //1.读取mybatis框架的配置文件 String resource = "com/myh/映射文件的元素/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); //2.根据配置文件“构建会话工厂 : SqlSessionFactory ” SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //3.通过SqlSessionFactory(会话工厂)创建SqlSession("会话"对象) SqlSession sqlSession = sqlSessionFactory.openSession(); User user1 = (User)sqlSession.selectOne("UserMapper.selectUser_resultType", 2); /** 此处输出的内容为 : null ,因为字段名和属性名 不一样,数据无法映射成功,最后输出的内容为 : null */ System.out.println("从数据库中查询到的数据为(通过resultType获得): "+user1); /** 此处输出的内容为 : "查询到的数据",即使“属性名” 和 “字段名”没有保持一致,但通过resultMap元素的配置,查询到的数据依然能 映射到POJO类中。 */ User user2 = (User)sqlSession.selectOne("UserMapper.selectUser_resultMap", 2); System.out.println("从数据库中查询到的数据为(通过resultMap获得): "+user2); //4.关闭SqlSession sqlSession.close(); } }
控制台输出结果为 :