现在许多框架都提供了两种配置方式,文件配置和注解配置
文件配置主要使用xml文件,其他的还有properties,yml等。注解则是嵌入代码中。看到这儿应该明白,注解配置是与代码嵌在一起,没有解耦。而配置文件则是与代码分离开来,但是在实际开发中,很少有这种情况:修改配置文件但不修改代码的。
Mybatis也提供了注解和文件两种配置。这儿着重介绍文件配置的方式,因为Mybatis主要就是使用文件配置,如果使用注解,那么Myabtis的sql语句与代码分离这个优势就不存在了。
Mybatis的配置文件主要分为两部分,mybatis全局配置文件和mapper配置文件。
1、Mybatis的全局配置文件:Mybatis-config.xml
所有的配置都必须在configuration标签之间。
1.1、Properties配置。
前面用到了properties这个标签,在resources属性中引入了db.properties。这个标签顾名思义就是配置属性的。
可以使用resource属性引入配置文件,也可以使用url属性引入,但注意resource和url两个属性不能同时指定,虽然你可以在配置文件中这样书写(不会报错),但是当初始化时就会抛出异常。初始化代码为org.apache.ibatis.builder.xml.XMLConfigBuilder的propertiesElement(XNode)方法,代码如下:
if (context != null) {
Properties defaults = context.getChildrenAsProperties();
String resource = context.getStringAttribute("resource");
String url = context.getStringAttribute("url");
//同时指定了resource和url会报错
if (resource != null && url != null) {
throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference. Please specify one or the other.");
}
if (resource != null) {
defaults.putAll(Resources.getResourceAsProperties(resource));
} else if (url != null) {
defaults.putAll(Resources.getUrlAsProperties(url));
}
Properties vars = configuration.getVariables();
if (vars != null) {
defaults.putAll(vars);
}
parser.setVariables(defaults);
configuration.setVariables(defaults);
}
也可以使用property指定单个属性,但注意代码中的property会覆盖resource或者url引入的配置,也会覆盖property标签配置的属性,这是因为解析顺序为:property标签-->引入的配置文件 --> 代码中的properties。且是使用Properties这个类来存储的,关于Properties类,可以自己使用一下。可以使用${}引用前面配置的属性。
值得注意的是:如果要使用properties这个标签,那么必须将该标签放在其他标签之前,且一个配置文件中只能出现一次properties标签。
1.2 settings全局的设置
注意:settings里面至少包含一个setting
1.3 typeAliases别名配置,这个标签存在的意义仅是为了减少冗余。
正如上篇看到的,如果不配置这个属性,那么配置文件中就必须使用类的全称限定名。例如配置这个属性前使用org.yamikaze.model.User,配置后使用User,大大减少了冗余。也可以使用typeAlias配置单个别名。如下所示:
注意:这个标签配置最多出现一次,且typeAlias必须在package前面,而且不能有相同的别名,否则报错。
可以配置多个环境,但是只能使用其中一个。环境一定要配置环境的id,事务管理器以及数据源。同时一定要指定默认的环境。事务管理器一般使用JDBC来提交回滚,数据源Mybatis内置了三种,POOLED、UNPOOLED、JNDI。当然你可以使用第三方数据源,比如DBCP、C3P0、Druid等。
1.5、映射器mappers。
用于指定实体类对应的配置文件或者接口。
注意:如果你使用的是注解配置,那么指定接口,否则指定配置文件。一般使用resource指定配置文件。
configuration下面还有许多标签配置,单个人感觉不是很常用。更多配置参考http://www.mybatis.org/mybatis-3/zh/index.html。
2、实体类mapper文件配置。
这个配置文件配置了实体类相关的所有sql语句以及返回结果集。
所有的配置都应该放在mapper标签之间,如:
insert into t_user(username,password,sex) values(#{username},#{password},#{sex})
2.1、insert标签、update标签、delete标签
这几个标签用于向数据库插入数据、更新数据、删除数据。为什么要把他们放在一起?这是因为在配置文件中它们的配置几乎是一致的,差别在于sql语句的不同。如果你感兴趣的话,可以查看Mybatis的源代码,你会发现虽然可以调用session.insert()、session.delete(),但是最后实际调用的都是session的update方法。
每个标签都共有的属性:
id:每一个标签必须制定id,同一个配置文件不能指定相同的id,但不同的配置文件可以相同,例如,我们可以统一约定 插入语句id为save或者insert,更新语句id为update,删除语句id为delete。
parameterType:参数类型,Mybatis内置了许多java类型,例如string、integer(int)、map等,你也可以使用你自己定义的实体类(注意配置别名)。实际上,你可以不在配置文件中配置这个属性,因为Myabtis可以通过TypeHandler判断具体传入的类型。但最好还是指定,这样比较好维护sql语句。还有一个parameterMap也可以指定参数类型,但这个属性在3版本已经被声明过时了。
useGeneratedKeys和keyProperty,useGenerateKeys表示是否使用数据库自动生成的主键,默认是为false的,如果设置为true,同时指定了keyProperty,那么会将自动生成后的主键注入到指定的属性中,如下:
public static void main(String[] args) {
IUserDao userDao = new UserDao();
User u = new User();//u的Id为0,因为没有指定
u.setUsername("tom");
u.setSex("man");
u.setPassword("951001");
userDao.save(u); //save语句设置了useGeneratedKeys为true,keyProperty="id"
System.out.print(u.getId()); //u的id为9,这是第9条数据
}
但是注意:这两个属性仅对insert和update语句有效。
timeout属性:指定超时时间,会覆盖前面全局配置。
statementType:指定使用statement还是preparedstatement还是callablestatement,默认为preparedstatement。
一般可以这样配置:
INSERT INTO t_user(username,password,sex) VALUES(#{username},#{password},#{sex})
DELETE FROM t_user WHERE id = #{id}
UPDATE t_user SET username = #{username},password = #{password},sex = #{sex}
WHERE id = #{id}
注意:这三条语句可以有返回值,但是返回的是数据库数据的修改行数。
2.2、select标签。
这个标签用于查找数据,使用频率最高的select语句。它的通用配置与insert是一致的,但不同于insert的是它有返回值。同时select语句的查询以及结果映射也是Mybatis研究的焦点。
resultType:返回类型,如果是返回集合,那么应该是集合包含的具体类型,例如:返回List
resultMap:如果需要返回更复杂的类型,那么请使用resultMap。resultMap需要在配置文件中手动配置。
2.3、sql标签。
这个标签用于定义一些可重用的sql片段。比如,查找用户点赞或者收藏的文章列表时,查找出的数据类型是一样的,但是关联的表不一样,那么可以将查询的一部分提取出来重用。 例如:
SELECT ${tableName1}.*,${tableName2}.*
2.4、resultMap标签。
前面select标签的resultMap属性值必须是resultMap定义的。
我们先来看下resultMap的简单结果映射。
看着这条sql语句没有使用resultMap,但其实Mybatis会在幕后自动创建一个resultMap来映射。例如:数据库行名为username,对应的属性名为username那么就会精确到username属性中。也许你数据库的是user_name,那么你可以这样使用:
或者配置resultMap:
然后在select标签的返回值使用userResult就ok了,你注意到了autoMapping=true吗?设置为true会自动映射没有用result子标签指定的属性
IDCard实体类:
package org.yamikaze.model;
import java.util.Date;
/**
* Created by yamikaze on 2017/7/12.
*/
public class IDCard {
private Long no; //卡的编号
private Long uid; //关联用户的id
private Date createTime; //绑定卡的时间
private String type; //卡的类型
//setter & getter方法略
}
Message.java
package org.yamikaze.model;
import java.util.Date;
/**
* Created by yamikaze on 2017/7/12.
*/
public class Message {
private Long id; //留言Id
private Long uid; //留言用户的id
private String content; //留言内容
private Date createTime;//留言时间
private String ipAddress;//留言ip地址
private Long mid; //如果为null表示留言,不为null表示是对留言的留言
//setter & getter方法略
}
User.java
package org.yamikaze.model.model0;
import org.yamikaze.model.IDCard;
import org.yamikaze.model.Message;
import java.util.List;
/**
* Created by yamikaze on 2017/7/12.
*/
public class User {
private Long id; //用户id
private String username; //用户名
private String nickname; //用户昵称
private String password; //用户密码
private String sex; //用户性别
private IDCard idCard; //用户关联的IDCard对象
private List messages;//用户的留言
public User(Long id,String username,String password) {
this.id = id;
this.username = username;
this.password = password;
}
//setter & getter方法略
}
注意:记得在mybatis-config中配置别名,以及将相对应的实体类mapper文件加入到mappers中。
User表结构为:
开始编写Mapper文件吧!
MessageMapper文件与IDCardMapper文件略(里面只用添加一个insert方法)
UserMapper文件
insert into t_user0(username,nickname,password,sex,id)
value (#{username},#{nickname},#{password},#{sex},#{id})
测试代码(请在测试前录入相应测试数据):
public static void load() {
InputStream is = null;
SqlSessionFactory factory = null;
SqlSession session = null;
try {
is = Resources.getResourceAsStream("mybatis-config.xml");
factory = new SqlSessionFactoryBuilder().build(is);
session = factory.openSession();
User0 user = (User0)session.selectOne("load",1L);
System.out.println(user.getSex());
System.out.println(user.getMessages().size());
} catch (IOException e) {
e.printStackTrace();
} finally {
if(session!=null) session.close();
}
}
结果:
嵌套查询会重新发sql语句查询,而结果嵌套需要我们手动为结果配置别名,比如测试的IDCard类与Message类都有no属性,那么要使用结果嵌套我们就需要这样指定别名
select card.no as card_no,message.no as message_no.......这样的方式。同时建议开启autoMapping=true,这样可以减少配置。
3、缓存配置。
在mapper映射文件中开启缓存只需要加入这一句:
关于cache标签:
flushInterval:刷新间隔。
size:引用对象的数量,必须是整数。
readOnly是否可读可写。
eviction:回收策略,默认为LRU
当然你可以自定义缓存,使用type属性来指定。例如:
这个类必须实现
org.mybatis.cache.Cache接口,如果要向实现类传值的话,可以使用property标签,如下:
注意:使用缓存不要忘了在mybatis-config.xml文件中开启全局缓存。
Mybatis常用的配置基本就这些了,因个人原因可能还有一些其他的配置没有提到的。
如果想了解Mybatis具体有哪些配置的话可以访问http://www.mybatis.org/mybatis-3/zh/index.html