mybatis(下篇)

主配置文件详解

(我们本章节主要讲解的mybatis-config.xml各配置)
Configuration
The MyBatis configuration contains settings and properties that have a dramatic effect on how MyBatis behaves. The high level structure of the document is as follows:
·configuration
· properties
·property
· settings
· typeAliases
· typeHandlers
· objectFactory
· plugins
· environments
 ·environment
·transactionManager
·dataSource
· databaseIdProvider
· mappers

(我们下面讲解的各标签在mybatis-config.xml文件添加顺序是固定的,不能打乱:
- The content of element type "configuration" must match 
"(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,proxyFactory?,plugins?,environments?,databaseIdProvider?,mappers?)".
- Start tag of element <configuration>)

4.1 properties -- 参数值

三种方式:
1、引入指定文件
<properties resource="mysql.properties" />
<properties>元素允许在主配置文件之外提供一个properties格式对应文件,从而使得主配置文件更加通用。这样对部署非常有用。
两个属性
resource--类路径上的一个资源
url -- 统一资源定位符
最后通过名称来引用这些属性。

2、内部配置
property:
这是通过外部文件引入的方式,我们可以在properties内创建内部property元素,如:
<properties resource="org/mybatis/example/config.properties">
<property name="username" value="dev_user"/>
<property name="password" value="F2Fa3!33TYyg"/>
</properties>

3、在Java代码中传入
Properties can also be passed into the SqlSessionBuilder.build() methods. For example:
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, props);
// ... or ...
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment, props);

使用方式:
然后可以使用配置文件里的属性值或者使用内部方式加入的属性值,来给为配置文件进行动态配置:

[html]  view plain copy
  1. <dataSource type="POOLED">  
  2.     <property value="${driver}" name="driver" />  
  3.     <property value="${url}" name="url" />  
  4.     <property value="${username}" name="username" />  
  5.     <property value="${password}" name="password" />  
  6. </dataSource>  
在这个例子中的用户名和密码等将被替换成属性元素中设置的值。

问题:
当上面三种方式出现重复的值如何处理?
首先他们三者的加载顺序是:内部配置 --> 引入指定文件 --> 在Java代码中传入。若在加载过程中出现重复值,后者会覆盖前者。

4.2 settings -- 全局配置

<settings>元素添加若干属性来设置这些可选项。MyBatis有许多配置项可用,并且每个配置项对于这个SQLMap实例来说都是全局的。
这些都是非常重要的配置,用于指定MyBatis在运行时的行为。如果不指定,会使用默认值。
[html]  view plain copy
  1.   
[html]  view plain copy
  1. <settings>  
  2.   
  3.         <!-- 在全局范围内"启用或禁用任何高速缓存" - 应该是除了session;默认值true -->  
  4.         <setting name="cacheEnabled" value="true" />  
  5.   
  6.         <!-- 延迟加载是一种只加载必要信息而推迟加载其他未明确请求的数据的技术。也就是说,除非绝对需要,否则应用程序加载的数据越少越好。 lazyLoadingEnabled配置项用于指定当存在相关联的已映射语句时,"是否使用延迟加载"。其有效值为true或false,默认值为true。 -->  
  7.         <!-- <setting name="lazyLoadingEnabled" value="true" /> -->  
  8.   
  9.         <!-- 开启懒加载。默认值为true -->  
  10.         <!-- <setting name="aggressiveLazyLoading" value="true" /> -->  
  11.   
  12.         <!-- 指定对象中什么方法会触发延迟加载。值为以逗号分隔的方法名称列表。 -->  
  13.         <!-- <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"   
  14.             /> -->  
  15.   
  16.         <!-- 是否允许一个statement返回多个ResultSets,但是需要驱动程序支持。默认值true -->  
  17.         <setting name="multipleResultSetsEnabled" value="true" />  
  18.   
  19.         <!-- 是否可以使用别名获取,具体取决于驱动程序是否支持。默认为true -->  
  20.         <setting name="useColumnLabel" value="true" />  
  21.   
  22.         <!-- 允许JDBC 生成主键。需要驱动器支持。如果设为了true,这个设置将强制使用被生成的主键,有一些驱动器不兼容不过仍然可以执行(比如Derby)。默认值false -->  
  23.         <!-- <setting name="useGeneratedKeys" value="false" /> -->  
  24.   
  25.         <!-- 指定是否以及如何自动映射数据字段到POJO字段。三个选项:NONE不自动映射;PARTIAL将只自动映射简单的,没有嵌套的结果;FULL将自动映射任何(包含嵌套或以其他方式)复杂的结果。默认值PARTIAL -->  
  26.         <setting name="autoMappingBehavior" value="PARTIAL" />  
  27.   
  28.         <!-- 默认执行方式。三种方式:SIMPLE默认没有特殊处理;REUSE重用PreparedStatements;BATCH重用statements和进行批量更新。默认值:SIMPLE -->  
  29.         <setting name="defaultExecutorType" value="SIMPLE" />  
  30.   
  31.         <!-- 设置Statement默认数据库响应超时时间,单位为妙。 -->  
  32.         <setting name="defaultStatementTimeout" value="1" />  
  33.   
  34.         <!-- 嵌套结果映射,是否使用rowbounds进行分页,建议不要使用rowbounds进行分页,特别是SQL执行返回结果很大的情况下(因为它用的是返回后截取-逻辑分页)。默认值false -->  
  35.         <setting name="safeRowBoundsEnabled" value="false" />  
  36.   
  37.         <!-- 进行自动映射时,数据以下划线命名,如数据库返回的"order_address"命名字段是否映射为class的"orderAddress"字段。默认为false -->  
  38.         <setting name="mapUnderscoreToCamelCase" value="false" />  
  39.   
  40.         <!-- MyBatis使用本地缓存来提高重复查询的速度。两个选项:SESSION,和我们hibernate里的session类似,在同一个session中共享;STATEMENT,只在同一个statement中共享。默认值SESSION -->  
  41.         <setting name="localCacheScope" value="SESSION" />  
  42.   
  43.         <!-- 有些驱动程序在返回值为NULL时需要指定JDBC类型,大部分情况下是:NULL、VARCHAR或OTHER。默认值OTHER -->  
  44.         <setting name="jdbcTypeForNull" value="OTHER" />  
  45.   
  46.     </settings>  



4.3 typeAliases -- 别名

一个type alias是为一个Java Type定义的短名称。
除非别无选择,否则没人愿意输入像这样一个长串的名字:com.partner4java.demo.entity.Account。
<typeAlias>元素允许定义别名,这样就可以直接用account来代替刚才的那个冗长的全限定类名了。
<typeAlias alias="user" type="com.partner4java.demo2.User" />
当在配置过程中定义account这个别名之后,就可以在任何时候使用他了,每当你必须提供一个数据类型时,都可以使用全限定类名或者别名来告诉iBATIS你想使用哪个数据。
iBATIS为若干类型定义了别名,以免除开发人员必须手工添加这些别名的麻烦。
Demo:
<!-- 注意一点,这个放在properties后面,不然会加载出错 -->
<typeAliases>
<typeAlias alias="user" type="com.partner4java.demo2.User" />
</typeAliases>

我们加了上面别名之后,就可以修改User.xml文件的返回类型<select id="selectUser" resultType="user">

我们可以使用更简洁的方式,指定一个包,MyBatis会自动扫描包下的所有类,以非限定类名首字母小写来作为别名,当然你也可以使用@Alias注解手工指定:
[html]  view plain copy
  1. <!-- mybatis-config.xml -->  
  2. <typeAliases>  
  3.     <package name="com.partner4java"/>  
  4. </typeAliases>  
  5.   
  6. @Alias("user")  
  7. public class User {  
  8.     ...  
  9. }  

There are many built-in type aliases for common Java types. They are all case insensitive, note the
special handling of primitives due to the overloaded names.
Alias  Mapped Type
_byte  byte
_long  long
_short  short
_int  int
_integer  int
_double  double
_float  float
_boolean  boolean
string  String
byte  Byte
long  Long
short  Short
int  Integer
integer  Integer
double  Double
float  Float
boolean  Boolean
date  Date
decimal  Decimal
bigdecimal  BigDecimal
object  Object
map  Map
hashmap  HashMap
list  List
arraylist  ArrayList
collection  Collection
iterator  Iterator

(学习到这里,你应该转到“自动映射”,学完自动映射然后再返回这里)

4.4 typeHandlers -- 类型处理器

MyBatis使用类型处理器(type handler)将数据从数据库特定的数据类型转换为应用程序中的数据类型,这样你就可以创建一个以一种尽可能透明的方式来使用数据库的应用程序。
类型处理器本质上就是一个翻译器(translator)--他将数据库返回的结果集合中的列“翻译”为相应的JavaBean中的字段。

MyBatis自带的类型处理器:
Type Handler  Java Types  JDBC Types
BooleanTypeHandler  java.lang.Boolean,boolean Any compatible BOOLEAN
ByteTypeHandler  java.lang.Byte, byte  Any compatible NUMERIC or BYTE
ShortTypeHandler  java.lang.Short, short  Any compatible NUMERIC or SHORT INTEGER
IntegerTypeHandler  java.lang.Integer, int  Any compatible NUMERIC or INTEGER
LongTypeHandler  java.lang.Long, long  Any compatible NUMERIC or LONG INTEGER
FloatTypeHandler  java.lang.Float, float  Any compatible NUMERIC or FLOAT
DoubleTypeHandler  java.lang.Double, double  Any compatible NUMERIC or DOUBLE
BigDecimalTypeHandler  java.math.BigDecimal  Any compatible NUMERIC or DECIMAL
StringTypeHandler  java.lang.String  CHAR, VARCHAR
ClobTypeHandler  java.lang.String  CLOB, LONGVARCHAR
NStringTypeHandler  java.lang.String  NVARCHAR, NCHAR
NClobTypeHandler  java.lang.String  NCLOB
ByteArrayTypeHandler  byte[]  Any compatible byte stream type
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, or unspecified
EnumTypeHandler  Enumeration Type  VARCHAR any string compatible type, as the code is stored (not the index).
EnumOrdinalTypeHandler  Enumeration Type  Any compatible NUMERIC or DOUBLE, as the position is stored(not the code itself).

你可以覆盖上面的类型处理器,也可以自定义一个类型处理器。
如果这么做,你只需要三步:
1、写一个类继承自org.apache.ibatis.type.BaseTypeHandler;
2、使用@MappedJdbcTypes注解给该类指定要处理的类型;
3、在XML中配置一个本类的<typeHandler>标签,然后指定扫描指定包内的。
Demo:
[html]  view plain copy
  1. // ExampleTypeHandler.java  
  2. @MappedJdbcTypes(JdbcType.VARCHAR)  
  3. public class ExampleTypeHandler extends BaseTypeHandler<String> {  
  4.     @Override  
  5.     public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType ps.setString(i, parameter);  
  6.     }  
  7.     @Override  
  8.     public String getNullableResult(ResultSet rs, String columnName) throws SQLException return rs.getString(columnName);  
  9.     }  
  10.     @Override  
  11.     public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException return rs.getString(columnIndex);  
  12.     }  
  13.     @Override  
  14.     public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException return cs.getString(columnIndex);  
  15.     }  
  16. }  
  17.   
  18.   
  19. <typeHandlers>  
  20.     <typeHandler handler="org.mybatis.example.ExampleTypeHandler"/>  
  21. </typeHandlers>  


第2步你也可以省略,在<typeHandler>标签中使用jdbcType属性指定。
第3步如果你想扫描指定包下的所有带有@MappedJdbcTypes注解的类为类型处理器,不单独声明,可替换为:
<!-- mybatis-config.xml -->
<typeHandlers>
<package name="org.mybatis.example"/>
</typeHandlers>

4.5 objectFactory

Each time MyBatis creates a new instance of a result object, it uses an ObjectFactory instance to do so. 
The default ObjectFactory does little more than instantiate the target class with a default constructor, or a parameterized constructor if parameter mappings exist. 
If you want to override the default behaviour of the ObjectFactory, you can create your own. For example:
[html]  view plain copy
  1. // ExampleObjectFactory.java  
  2. public class ExampleObjectFactory extends DefaultObjectFactory {  
  3.     public Object create(Class type) {  
  4.         return super.create(type);  
  5.     }  
  6.     public Object create(Class type, List<Class> constructorArgTypes, List<Object> constructorArgs) return super.create(type, constructorArgTypes, constructorArgs);  
  7.     }  
  8.     public void setProperties(Properties properties) {  
  9.         super.setProperties(properties);  
  10.     }  
  11. }  
  12.   
  13. <!-- mybatis-config.xml -->  
  14. <objectFactory type="org.mybatis.example.ExampleObjectFactory">  
  15.     <property name="someProperty" value="100"/>  
  16. </objectFactory>  

The ObjectFactory interface is very simple. It contains two create methods, one to deal with the
default constructor, and the other to deal with parameterized constructors. Finally, the setProperties
method can be used to configure the ObjectFactory. Properties defined within the body of the
objectFactory element will be passed to the setProperties method after initialization of your
ObjectFactory instance.

4.6 plugins

不做讨论,当你对MyBatis足够熟悉的时候可以自行研究。


4.7 environments -- 多数据源配置

environment:
MyBatis的可配置多个环境。
这可以帮助你解决应用场景中很多问题。
例如,你可能有不同的配置,为您的开发,测试和生产环境。
(但是,在你使用时只能选择其中一种)
Demo:
[html]  view plain copy
  1. <!-- 配置数据源相关的信息 -->  
  2. <environments default="demo1">  
  3.     <environment id="demo1">  
  4.         <transactionManager type="JDBC" />  
  5.         <dataSource type="POOLED">  
  6.             <property value="${driver}" name="driver" />  
  7.             <property value="${url}" name="url" />  
  8.             <property value="${username}" name="username" />  
  9.             <property value="${password}" name="password" />  
  10.         </dataSource>  
  11.     </environment>  
  12.     <environment id="demo2">  
  13.         <transactionManager type="JDBC" />  
  14.         <dataSource type="POOLED">  
  15.             <property value="${driver}" name="driver" />  
  16.             <property value="${url}" name="url" />  
  17.             <property value="${username}" name="username" />  
  18.             <property value="${password}" name="password" />  
  19.         </dataSource>  
  20.     </environment>  
  21. </environments>  

比如上面这个,他会默认使用demo1,但是你如果想代码指定demo2,可以调用SqlSessionFactoryBuilder().build(InputStream inputStream, String environment)接收String类型environment参数的方法。

<transactionManager>元素:
由于MyBatis就是为了使数据库访问变得更加简单而设计的,因此他将为你处理所有的数据库事务。
使用MyBatis时,有哪些事务管理器实现类是可用的。可以考虑使用MyBatis那些预定义的事务管理器。
<transactionManager>元素的type属性就是用于指定应该使用哪个事务管理器的。
iBATIS提供了若干内建事务管理器实现:
JDBC 用于提供简单的基于jdbc的事务管理。大多数情况下,使用这个事务管理器就足够了。
EXTERNAL 用于提供非事务管理,并假定管理事务的是应用程序,而不是MyBatis

对于事务管理器,另一个可用的设置就是commitRequired属性,该属性可被设置为true或者false,默认是为false。
他主要用于那些要求在释放某个连接之前必须提交(commit)或者回退(rollback)的情况。
对于某些操作(例如选择和存储过程调用),通常并不需要事务,因此一般会将其忽略。
某些数据库驱动程序(例如Sybase驱动程序)不会轻易释放连接,直至该连接的每个已启动事务都已提交或回退。在这些情况下,就可以使用commitRequired属性来强制释放连接,即使在那些通常需要在一个事务中释放却没用释放的情况。

<dataSource>元素
在java中,使用连接池的标准方法就是通过javax.sql.DataSource对象。
事务管理的<dataSource>元素有一个属性,用来告诉MyBatis他应该为其数据源工厂实例化并使用哪个类。
<dataSource>元素名字很容易仍人产生误解,因为实际上他并不是用来定义DataSource,而是用来定义DataSourceFactory实现类,MyBatis将用这个实现类来创建实际的DataSource。
MyBatis具有三种数据源工厂实现类:
UNPOOLED -- 最简单的方式,没有加入连接池
有五个基本配置:
·driver – This is the fully qualified Java class of the JDBC driver (NOT of the DataSource class
if your driver includes one).
· url – This is the JDBC URL for your database instance.
·username – The database username to log in with.
·password - The database password to log in with.
·defaultTransactionIsolationLevel – The default transaction isolation level for
connections.
Optionally, you can pass properties to the database driver as well. To do this, prefix the properties
with driver., for example:
·driver.encoding=UTF8
This will pass the property encoding, with the value UTF8, to your database driver via the
DriverManager.getConnection(url, driverProperties) method.

POOLED -- 这是一个加入了连接池策略的的方式
在上面五个基本配置外又增加了:
·poolMaximumActiveConnections – This is the number of active (i.e. in use) connections that
can exist at any given time. Default: 10
·poolMaximumIdleConnections – The number of idle connections that can exist at any given
time.
·poolMaximumCheckoutTime – This is the amount of time that a Connection can be "checked
out" of the pool before it will be forcefully returned. Default: 20000ms (i.e. 20 seconds)
·poolTimeToWait – This is a low level setting that gives the pool a chance to print a log status
and re-attempt the acquisition of a connection in the case that it’s taking unusually long (to avoid
failing silently forever if the pool is misconfigured). Default: 20000ms (i.e. 20 seconds)
·poolPingQuery – The Ping Query is sent to the database to validate that a connection is in
good working order and is ready to accept requests. The default is "NO PING QUERY SET",
which will cause most database drivers to fail with a decent error message.
·poolPingEnabled – This enables or disables the ping query. If enabled, you must also set the
poolPingQuery property with a valid SQL statement (preferably a very fast one). Default: false.
·poolPingConnectionsNotUsedFor – This configures how often the poolPingQuery
will be used. This can be set to match the typical timeout for a database connection, to
avoid unnecessary pings. Default: 0 (i.e. all connections are pinged every time – but only if
poolPingEnabled is true of course).

JNDI -- This implementation of DataSource is intended for use with containers such as EJB or
Application Servers that may configure the DataSource centrally or externally and place a reference to
it in a JNDI context. This DataSource configuration only requires two properties:
·initial_context – This property is used for the Context lookup from the InitialContext
(i.e. initialContext.lookup(initial_context)). This property is optional, and if omitted, then the
data_source property will be looked up against the InitialContext directly.
·data_source – This is the context path where the reference to the instance of the DataSource
can be found. It will be looked up against the context returned by the initial_context lookup, or
against the InitialContext directly if no initial_context is supplied.
Similar to the other DataSource configurations, it’s possible to send properties directly to the
InitialContext by prefixing those properties with env., for example:
·env.encoding=UTF8
This would send the property encoding with the value of UTF8 to the constructor of the
InitialContext upon instantiation.


4.8 databaseIdProvider -- 不同库SQL匹配

我们可以配置不同数据库的不同SQL,会根据数据库引擎进行决定。
<databaseIdProvider type="VENDOR">
<property name="SQL Server" value="sqlserver"/>
<property name="DB2" value="db2"/>
<property name="Oracle" value="oracle" />
</databaseIdProvider>


4.9 mappers -- 引入SQL

前面我们已经提到了,有两种使用方式:
[html]  view plain copy
  1. 1、在XML中配置SQL,需要挨个在mybatis-config.xml中指定  
  2. 如:  
  3. <mappers>  
  4.     <mapper resource="com/partner4java/demo2/User.xml" />  
  5. </mappers>  
  6.   
  7. 2、使用注解管理SQL,直接指定要扫描的jar包  
  8. <mappers>  
  9.     <!-- 指定扫描指定目录的注解 -->  
  10.     <package name="com.partner4java" />  
  11. </mappers>  
  12.   
  13. public interface UserMapper {  
  14.     //我们用到了注解@Select,参数问SQL  
  15.     @Select("select * from user where id = #{id}")  
  16.     public User selectUserByID(int id);  
  17. }  


自动映射

从数据库中获取数据是一个应用程序中最基本的操作之一。MyBatis框架使得编写大部分的SELECT语句都毫不费力,并且提供了很多特性,使得你几乎可以从数据库中得到任何想要的数据。

1.使用XML
正如我们helloworld里面的一样,在XML中配置select语句。
查询参数替代(#{})符号。

[html]  view plain copy
  1. <!-- User.xml -->  
  2. <!-- parameterType为我们参数类型 -->  
  3. <select id="selectUserByID" resultType="user" parameterType="int">  
  4.     select * from user where id = #{value}  
  5. </select>  
  6.   
  7. public static void main(String[] args) {  
  8.     InputStream is = null;  
  9.     SqlSessionFactory sqlSessionFactory = null;  
  10.     SqlSession session = null;  
  11.     try {  
  12.         is = Resources.getResourceAsStream("mybatis-config4.xml");  
  13.         sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);  
  14.         session = sqlSessionFactory.openSession();  
  15.         //执行一个唯一返回值的查询;user.selectUserByID由两部分组成:“user.”为我们的namespace;“selectUserByID”为我们具体id。  
  16.         User user = session.selectOne("user.selectUserByID", 1);  
  17.         System.out.println(user);  
  18.     } catch (IOException e) {  
  19.         e.printStackTrace();  
  20.     }finally{  
  21.         try {  
  22.             is.close();  
  23.         } catch (IOException e) {  
  24.             e.printStackTrace();  
  25.         }finally{  
  26.             session.close();  
  27.         }  
  28.     }  
  29. }  


问题:MyBatis框架是如何处理该语句的?
首先,MyBatis将查找名为user.selectUserByID的已映射语句,并把#{value}占位符变换为一个预备语句参数,就是转换成我们JDBC中所用的"?"格式。

2.使用注解的方式
我们的User.xml就不需要了,但是需要额外两步操作:
[html]  view plain copy
  1. 配置mybatis-config.xml  
  2. <mappers>  
  3.     <!-- 指定扫描指定目录的注解 -->  
  4.     <package name="com.partner4java" />  
  5. </mappers>  
  6.   
  7. 新建Mapper接口类:  
  8. (Mapper接口只是定义了各种查询的格式,含义很容易理解,方法参数就是为我们的SQL输入参数,返回值为SQL返回封装类型)  
  9. public interface UserMapper {  
  10.     //我们用到了注解@Select,参数问SQL  
  11.     @Select("select * from user where id = #{id}")  
  12.     public User selectUserByID(int id);  
  13. }  
  14.   
  15. 执行:  
  16. is = Resources.getResourceAsStream("mybatis-config5.xml");  
  17. sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);  
  18. session = sqlSessionFactory.openSession();  
  19. //指定全类名,加方法  
  20. User user = session.selectOne("com.partner4java.demo2.UserMapper.selectUserByID", 1);  
  21. System.out.println(user);  
  22.   
  23. 上面的执行,我们还可以进行修改,给session指定一个默认的Mapper接口类(这样每次执行都不需要再给全类名了,更简洁):  
  24. is = Resources.getResourceAsStream("mybatis-config5.xml");  
  25. sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);  
  26. session = sqlSessionFactory.openSession();  
  27. // 指定我们本session加载那个Mapper接口类  
  28. session.getMapper(UserMapper.class);  
  29. // 现在就只需要指定方法名  
  30. User user = session.selectOne("selectUserByID", 1);  
  31. System.out.println(user);  

3.自动结果映射
你可能已经注意到了,在所有我们给出的示例中都没有定义任何结果映射(result map),但是确实定义了结果类(result class)。
这种方式可行是因为MyBatis的自动结果映射机制,该机制会在已映射语句第一次被执行时,迅速的自动创建一个结果映射,然后将它应用于这条已映射语句。
可以有3种方式来使用这个特性:单列选择(single-column selection),固定多列选择(fixed-column list selection)和动态多列选择(dynamic-column list selection)。

单列选择 --
如果只想从某个查询中获取单例,就可以使用别名value作为一种快捷方式来完成此目的,这样就可以不需要定义复杂的结果映射了,只需要指定resultType:
<select id="selectUsernameByID" resultType="string" parameterType="int">
select username from user where id = #{value}
</select>

固定多列选择 -- 
如果需要查询多列,就可以使用自动结果映射来告诉MyBatis将列名作为bean的特性名,或者作为Map键。
当以这种方式映射到bean时,需要牢记一点:如果所选择的列在数据库中存在,但是不存在于你要映射的bean中,你将不会得到任何错误或警告,但是也得不到任何数据--这些数据只会静静的被忽略。
映射到Map对象时,也有相似的问题:尽管你仍然可以得到数据,但是这些数据不会在你所期望的地方。

动态多列选择 -- 
如果语句中被选择的那些字段列表可以在运行时改变,那么也可以使用动态结果映射。
(后面章节我们再具体说动态映射)

4.联结相关数据
有时候出于制作报表或者其他的什么目的,你可能想要把多个数据表联结起来,形成一个平板型结构。
MyBatis框架可以让你毫不费力地完成这项工作,因为它是将SQL语句映射为对象,而不是将数据库中的表映射为对象,所以映射表查询和映射多表查询几乎没有什么不同。


作用范围和生命周期

和Hibernate一样,我们类似Session各种资源的作用范围和生命周期是很重要的。

SqlSessionFactoryBuilder:
这个类在创建SqlSessionFactory之后没必要保持其“生命”,因为在创建了所需的SqlSessionFactory之后SqlSessionFactoryBuilder就没有任何作用。
SqlSessionFactoryBuilder建议在方法内使用即可,这样它的声明周期即为该方法执行过程。
保证其及时释放的意义在于,SqlSessionFactoryBuilder内持有了很多解析后的XML数据。

SqlSessionFactory:
创建SqlSession的工厂类。
犹如我们常用的工厂类,工厂是不建议销毁的,因为它要一直不断给我们创建所需对象。
最好的处理方式就是把SqlSessionFactory设置为单例的。

SqlSession:
每个线程都应该有自己的SqlSession实例。
SqlSession的实例不能共享,不是线程安全的。
因此,最好的范围是请求或方法的范围。
不要让一个SqlSession实例的引用一个静态字段,甚至一个类的实例字段。
在会话结束时,你要确保它的及时正确关闭。
如:
SqlSession session = sqlSessionFactory.openSession();
try {
// do work
} finally {
session.close();
}

Mapper Instances:
映射器是您创建的绑定映射statements的接口。
从SqlSession实例的映射接口收购。
它的生命周期是依附于SqlSession,因此不需要自己主动销毁。
映射器实例的最佳范围是方法范围(同SqlSession)。
也就是说,它在方法被请求时生效,被用于在该方法内,然后伴随方法结束时丢弃。
如:
SqlSession session = sqlSessionFactory.openSession();
try {
BlogMapper mapper = session.getMapper(BlogMapper.class);
// do work
} finally {
session.close();
}


Mapper XML Files 基础篇

1.Mapper XML Files
首先还是那句话MyBatis与O/RM不同:他不是直接把类映射为数据库表或者说把类的字段映射为数据库列,而是“把SQL语句的参数和结果映射为类”。
所以,我们主要的工作就是书写维护SQL。我们使用单独的XML文件维护一组相关SQL。也就是我们接下来学习的知识。
首先根元素为<mapper>,这是“奇迹”发生的地方,如果你和JDBC代码对比,你会立即看到节省了95%的代码,且它以SQL为核心,让我们可以寻求极致完美的完成自己的项目。

(我们这里不再一一阐述SqlSession的各方法作用,如果你学过JDBC,根据方法名很容易猜想作用,如果没学过JDBC请参考 http://blog.csdn.net/partner4java/article/details/8213119)

Mapper XML文件中只有很少数的一级标签:
·cache – 给定命名空间的缓存配置.
·cache-ref – 从另一个命名空间引用缓存配置.
·resultMap – 这些标签中最强大最复杂的标签,描述如何把返回的数据结果封装成Java对象.
·parameterMap – 已过时(用于描述Java对象如何对应数据库占位符).
·sql – 元素用于创建一个文本片段,而这些文本片段又可以组合起来以创建完整的SQL语句。.
·insert – A mapped INSERT statement.
·update – A mapped UPDATE statement.
·delete – A mapped DELETE statement.
·select – A mapped SELECT statement.

接下来的章节将详细描述这些元素:

·select
select将是我们最常用的元素,不过不用担心,因为它使用起来很简单。
For example:
<select id="selectPerson" parameterType="int" resultType="hashmap">
SELECT * FROM PERSON WHERE ID = #{id}
</select>
This statement is called selectPerson, takes a parameter of type int (or Integer), and returns a
HashMap keyed by column names mapped to row values.

Notice the parameter notation:
#{id}
This tells MyBatis to create a PreparedStatement parameter. With JDBC, such a parameter would be
identified by a "?" in SQL passed to a new PreparedStatement, something like this:
// Similar JDBC code, NOT MyBatis…
String selectPerson = "SELECT * FROM PERSON WHERE ID=?";
PreparedStatement ps = conn.prepareStatement(selectPerson);
ps.setInt(1,id);

在你使用MyBatis时上面的代码就不需要你写了,这也是我们使用MyBatis的原因。不过MyBatis帮你做的不仅如此,还包含结果的获取封装,这个只是我们后面会讲解。

The select element has more attributes that allow you to configure the details of how each statement should behave.
<select
id="selectPerson"
parameterType="int"
parameterMap="deprecated"
resultType="hashmap"
resultMap="personResultMap"
flushCache="false"
useCache="true"
timeout="10000"
fetchSize="256"
statementType="PREPARED"
resultSetType="FORWARD_ONLY">

Attribute Description
--------------------------------------------------------------------------
id A unique identifier in this namespace that can be used
to reference this statement.

parameterType The fully qualified class name or alias for the
parameter that will be passed into this statement.

parameterMap This is a deprecated approach to referencing an
external parameterMap. Use inline parameter
mappings and the parameterType attribute.

resultType The fully qualified class name or alias for the expected
type that will be returned from this statement. Note
that in the case of collections, this should be the
type that the collection contains, not the type of the
collection itself. Use resultType OR resultMap,
not both.

resultMap A named reference to an external resultMap.
Result maps are the most powerful feature of MyBatis,
and with a good understanding of them, many difficult
mapping cases can be solved. Use resultMap OR
resultType, not both.


flushCache Setting this to true will cause the local and 2nd level
caches to be flushed whenever this statement is
called. Default: false for select statements.


useCache Setting this to true will cause the results of this
statement to be cached in 2nd level cache. Default:
true for select statements.


timeout This sets the number of seconds the driver will wait for
the database to return from a request, before throwing
an exception. Default is unset (driver dependent).

fetchSize This is a driver hint that will attempt to cause the
driver to return results in batches of rows numbering
in size equal to this setting. Default is unset (driver
dependent).


statementType Any one of STATEMENT, PREPARED or CALLABLE.
This causes MyBatis to use Statement,
PreparedStatement or CallableStatement
respectively. Default: PREPARED.


resultSetType Any one of FORWARD_ONLY|
SCROLL_SENSITIVE| SCROLL_INSENSITIVE.
Default is unset (driver dependent).

databaseId In case there is a configured databaseIdProvider,
MyBatis will load all statements with no
databaseId attribute or with a databaseId that
matches the current one. If case the same statement
if found with and without the databaseId the latter
will be discarded.

我们挨个讲解一下select的这些属性标签:
id -- 一个命名空间里的唯一标识,你如果动手完成了前面的helloworld,这个没什么难理解的。

parameterType -- 自动映射参数类型,值为一个全类名或者alias别名。
(具体可参照iBatis中讲述的映射参数 http://blog.csdn.net/partner4java/article/details/8175358)
Demo1:简单类型
我们根据用户id查询对应用户信息:
这里的parameterType就为一个int类型
<select id="selectUsernameByID" resultType="string" parameterType="int">
select username from user where id = #{value}
</select>
String username = session.selectOne("user.selectUsernameByID", 1);

Demo2:自定义对象类型
我们查询一条Person数据,它的名字为hello,年龄为23。
<select id="queryPerson" resultType="person" parameterType="person">
select * from person where person_name = #{personName} and age = #{age}
</select>
Person person = new Person();
person.setPersonName("hello");
person.setAge(23);
System.out.println(sqlSession.selectList("person.queryPerson",person));
parameterType="person"我们指定了一个alias别名。

parameterMap -- 自定义参数映射(已过时)
前面parameterType借助了默认的反射机制,我们还可以自己指定各种参数对应关系和类型:
<parameterMap class="account" id="accountMap">
<parameter property="username" nullValue="hello" jdbcType="VARCHAR"/>
<parameter property="password" nullValue="123" jdbcType="VARCHAR"/>
<parameter property="groupname" nullValue="123" jdbcType="EMPLOYEE"/>
</parameterMap>
<select ... parameterMap="accountMap">
</select>

resultType -- 自动映射返回类型,值为一个全类名或者alias别名。
如果数据库返回列名称和POJO名字相对应,就应该直接使用本配置,MyBatis会自动把相匹配的数据塞进我们这里指定的类。
有时我们的类单词分隔符使用的下划线,而POJO是大写字母,我们可以在setting中配置mapUnderscoreToCamelCase(参考“配置详解”)。

resultMap -- 自定义返回映射
用法同parameterMap

cache将在后面章节具体学习。

timeout -- 最大相应时间。

fetchSize -- 
参照JDBC:setFetchSize 最主要是为了减少网络交互次数设计的。访问ResultSet时,如果它每次只从服务器上取一行数据,则会产生大量的开销。setFetchSize的意 思是当调用rs.next时,ResultSet会一次性从服务器上取得多少行数据回来,这样在下次rs.next时,它可以直接从内存中获取出数据而不 需要网络交互,提高了效率。 这个设置可能会被某些JDBC驱动忽略的,而且设置过大也会造成内存的上升。

databaseId -- 结合“配置详解”里的databaseIdProvider

·insert, update and delete
The data modification statements insert, update and delete are very similar in their implementation:
<insert
id="insertAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
keyProperty=""
keyColumn=""
useGeneratedKeys=""
timeout="20000">
<update
id="insertAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
timeout="20000">
<delete
id="insertAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
timeout="20000">


Attribute Description
id A unique identifier in this namespace that can be used
to reference this statement.

parameterType The fully qualified class name or alias for the
parameter that will be passed into this statement.


parameterMap This is a deprecated approach to referencing an
external parameterMap. Use inline parameter
mappings and the parameterType attribute.

flushCache Setting this to true will cause the 2nd level and local
caches to be flushed whenever this statement is
called. Default: true for insert, update and delete
statements.

timeout This sets the maximum time the driver will wait for the
database to return from a request, before throwing an
exception. Default is unset (driver dependent).


statementType Any one of STATEMENT, PREPARED or CALLABLE.
This causes MyBatis to use Statement,
PreparedStatement or CallableStatement
respectively. Default: PREPARED.


useGeneratedKeys (insert only) This tells MyBatis to use the JDBC
getGeneratedKeys method to retrieve keys
generated internally by the database (e.g. auto
increment fields in RDBMS like MySQL or SQL
Server). Default: false


keyProperty (insert only) Identifies a property into which
MyBatis will set the key value returned by
getGeneratedKeys, or by a selectKey child
element of the insert statement. Default: unset.


keyColumn (insert only) Sets the name of the column in the table
with a generated key. This is only required in certain
databases (like PostgreSQL) when the key column is
not the first column in the table.

The following are some examples of insert, update and delete statements.
<insert id="insertAuthor" parameterType="domain.blog.Author">
insert into Author (id,username,password,email,bio)
values (#{id},#{username},#{password},#{email},#{bio})
</insert>
<update id="updateAuthor" parameterType="domain.blog.Author">
update Author set
username = #{username},
password = #{password},
email = #{email},
bio = #{bio}
where id = #{id}
</update>
<delete id="deleteAuthor" parameterType="int">
delete from Author where id = #{id}
</delete>

这些元素的使用和我们select大致相同。
不同的是多了useGeneratedKeys属性标签:
用于在你插入的时候自动生成主键。
作何解释呢?比如你MySQL(支持自动生成主键),做了一条插入:
<insert id="addPerson" parameterType="person">
insert into person (id,person_name,password,age) values (#{id},#{personName},#{pass},#{age})
</insert>
Person person = new Person();
person.setPersonName("hello");
person.setAge(23);
sqlSession.insert("person.addPerson", person);
sqlSession.commit();
System.out.println(person.getId());
执行完,打印id为null。可是,有时候我们想获取id怎么呢?
<insert id="addPerson" parameterType="person" useGeneratedKeys="true" keyProperty="id">
insert into person (id,person_name,password,age) values (#{id},#{personName},#{pass},#{age})
</insert>
首先打开使用getGeneratedKeys -- useGeneratedKeys="true",然后告诉MyBatis哪个是你的主键keyProperty="id"(id为我们POJO主键属性名称)。
当然使用本特性的关键在于驱动程序支持。

MyBatis还对不支持自增长的数据库提供了支持,在insert标签中使用selectKey标签:
MyBatis has another way to deal with key generation for databases that don't support auto-generated
column types, or perhaps don't yet support the JDBC driver support for auto-generated keys.
Here's a simple (silly) example that would generate a random ID (something you'd likely never do,
but this demonstrates the flexibility and how MyBatis really doesn't mind):
<insert id="insertAuthor" parameterType="domain.blog.Author">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
select CAST(RANDOM()*1000000 as INTEGER) a from SYSIBM.SYSDUMMY1
</selectKey>
insert into Author
(id, username, password, email,bio, favourite_section)
values
(#{id}, #{username}, #{password}, #{email}, #{bio}, #{favouriteSection}
</insert>
In the example above, the selectKey statement would be run first, the Author id property would
be set, and then the insert statement would be called. This gives you a similar behavior to an autogenerated
key in your database without complicating your Java code.
The selectKey element is described as follows:
<selectKey
keyProperty="id"
resultType="int"
order="BEFORE"
statementType="PREPARED">
Attribute Description
--------------------------------------------------------
keyProperty The target property where the result of the
selectKey statement should be set.

resultType The type of the result. MyBatis can usually figure
this out, but it doesn't hurt to add it to be sure.
MyBatis allows any simple type to be used as the key,
including Strings.

order This can be set to BEFORE or AFTER. If set to
BEFORE, then it will select the key first, set the
keyProperty and then execute the insert
statement. If set to AFTER, it runs the insert statement
and then the selectKey statement – which is
common with databases like Oracle that may have
embedded sequence calls inside of insert statements.

statementType Same as above, MyBatis supports STATEMENT,
PREPARED and CALLABLE statement types that
map to Statement, PreparedStatement and
CallableStatement respectively.


·sql
This element can be used to define a reusable fragment of SQL code that can be included in other
statements. For example:
<sql id="userColumns"> id,username,password </sql>


The SQL fragment can then be included in another statement, for example:
<select id="selectUsers" parameterType="int" resultType="hashmap">
select <include refid="userColumns"/>
from some_table
where id = #{id}
</select>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值