MyBatis 学习笔记

MyBatis 是 iBatis 继任者。不知道为啥 iBatis 没戏了?MyBatis 是一种半自动的 ORM 机制。因为简单,现在也越来越多 JEE 程序所使用。

文档:http://www.mybatis.org/mybatis-3/index.html JavaDoc:http://www.mybatis.org/mybatis-3/apidocs/reference/packages.html

这里记录一下我的学习过程。

数据源怎么连接?

大家都知道配置文件的方式,这里就不赘述了。我们看看不用配置方式,写 Java 代码是怎么写的。

MyBatis 把数据源 DataSource 分为三种:

  • UNPOOLED    不使用连接池的数据源          ž
  • POOLED   使用连接池的数据源          ž
  • JNDI  使用 JNDI 实现的数据源

使用 UnpooledDataSource 的 getConnection(), 每调用一次就会产生一个新的 Connection 实例对象。MyBatis 创建了 DataSource 实例后,会将其放到 Configuration 对象内的 Environment 对象中供以后使用。如果有提供 Connection,怎么给 MyBatis 使用?答案是…… SqlSession openSession(Connection connection)。

另外源码中比较有意思的地方:元数据(metadata) ,本包对mybatis的其它包没有任何依赖,mybatis的其它包也不依赖于本包,即本包可以作为单独的组件或者工具类提出来。包含了3个元数据实体类和一个工厂类:Table 是对表的简单封装,包括 name,columns,primaryKey,catalog,schema;Column 是对列的简单封装,包括 name 和 type;Database是对数据库的简单封装,包括 catalog,schema,tables;DatabaseFactory 用来创建 Database 对象。缓存类也是(org.apache.ibatis.cache)。

业务逻辑什么时候调用 MyBastis?

如同 JDBC 不需要每次创建 Connection 一样,为达到数据库连接复用的效果,MyBastis 的数据服务也不需要每次创建。按照官方文档的介绍,下面这些都可以在程序初始化阶段生成,作为 static 成员公外界访问就好。

class AppStart {
    public static SqlSessionFactory sqlSessionFactory;
    private static Reader reader;
    static {
        try {
            Reader reader = Resources.getResourceAsReader("mybatic-config.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            // 由于使用了注解,所以在主配置文件没有mapper,需要在代码里显示注册该mapper接口
            sqlSessionFactory.getConfiguration().addMapper(IUserDAO.class);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    ……
}

SqlSession 则是可以反复创建,按照你的业务逻辑就好了。注意要记得每次使用 session 完毕都要将其关闭(session.close())。如下例子,我们使用了 Java 7 的 autoclose 机制,无须手动将其关闭。
LOGGER.info("插入一条新记录:" + entry.getName());

try (SqlSession session = App.sqlSessionFactory.openSession()) {
    if (!App.configuration.hasMapper(mapperClz)) {
        App.configuration.addMapper(mapperClz);
    }
    Mapper dao = session.getMapper(mapperClz);
    effectedRows = dao.create(entry);
    System.out.println(":::" + entry.getId()); // 自增的 id 会自动保存到 bean 之中!
    session.commit(); // 默认没有自动提交
} catch (Throwable e) {
    e.printStackTrace();
    throw new DaoException(e.getMessage());
}

SQL 映射

映射文件写好了,还要写接口。接口相当于 DAO。

我比较喜欢映射文件的地方就是:只需要写接口,不需要写实现!话说实现存在不存在呢?在啊? SQL 逻辑不就变相是一种“实现”吗?

除了 XML 映射文件外,还有两种方法构建映射关系。这两种方法又因为有互补性,所以你把它们当作一种方法也未尝不可。它们分别是直接在映射器接口中写 SQL 语句(通过 Annotation 注解),一种是利用 SqlBuilder 来创建 SQL 再由映射器接口来调用。所谓互补性,是因为我们无法在 Java 注解中写出 if... else,于是在 SQL Builder 里面直接写 Java if...else 就可以啦!


通过<sql>标签实现SQL语句复用

缓存模块则分为 SQ L语句缓存和查询数据缓存两种,由于 MyBatis 需要开发者自定义SQL语句,因此 SQL 语句缓存不用考虑;而查询数据缓存则被分为一级和二级缓存,一级缓存以事务为作用域,二级缓存以同一个映射集为作用域,而且二级缓存采用直写的方式处理缓存数据被修改和删除的情况。

返回集合时,DAO 接口不能写数组,例如 User[] 不行,得用 List 装载集合,如 List<User>。


其他资源

框架内调用 MyBatis:

/**
 * Configuration 需要设为 public 以便加入 mapper
 */
public static Configuration configuration;

/**
 * 一般用法 sqlSessionFactory.openSession()。注意,返回的 SqlSession 必须关闭
 */
public static SqlSessionFactory sqlSessionFactory;

/**
 * 初始化 MyBatis 数据链接服务
 * 
 * @param ds
 */
public static void init(DataSource ds) {
	Environment environment = new Environment("development", new JdbcTransactionFactory(), ds);
	configuration = new Configuration(environment);
	sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);

	// 打印数据库连接路径,以便了解
	try (Connection conn = environment.getDataSource().getConnection();){
		System.out.println("数据库连接字符串:" + conn + Constant.ConsoleDiver);
	} catch (SQLException e) {
		e.printStackTrace();
	} 
	
	// 如果要观察 MyBatis 动态生成的 SQL 语句,请打开控制台的输出。
	// org.apache.ibatis.logging.LogFactory.useStdOutLogging();
	// org.apache.ibatis.logging.LogFactory.useJdkLogging();


	System.out.println("数据库初始化成功!" + Constant.ConsoleDiver);
}

/**
 * 添加一个 Mapper(DAO)
 * @param clz
 */
public static void addDao(Class<? extends BaseDao<?, ?>> clz){
	if (clz != null && !configuration.hasMapper(clz))
		configuration.addMapper(clz);
}

JDBC 4 例子:

// https://docs.oracle.com/javase/tutorial/jdbc/basics/cachedrowset.html
// https://db.apache.org/derby/docs/10.9/ref/rrefjdbc4_1summary.html
// http://download.oracle.com/otn-pub/jcp/jdbc-4_1-mrel-spec/jdbc4.1-fr-spec.pdf
public static void create() {
	try (JdbcRowSet jdbcRs = RowSetProvider.newFactory().createJdbcRowSet();) {

		// 创建一个 JdbcRowSet 对象,配置数据库连接属性
		jdbcRs.setUrl("jdbc:derby:helloDB;");
		// jdbcRs.setUsername(username);
		// jdbcRs.setPassword(password);
		jdbcRs.setCommand("select name from hellotable");

		jdbcRs.execute();
		while (jdbcRs.next()) {
			System.out.println(jdbcRs.getString(1));
		}
		// delete the table
		// s.execute("drop table hellotable");
		// System.out.println("Dropped table hellotable");

		// rs.close();

		// DriverManager.getConnection("jdbc:derby:;shutdown=true");
	} catch (SQLException e) {
		// 通过应用 JDBC 4.0, 您现在不需太多代码即可以获取及遍历异常链在以往的版本中, 您在遍历异常链时,必须手工的调用
		// getNextException 方法才能得到相同的效果
		for (Throwable ex : e) {
			System.err.println("Error encountered: " + ex);
		}
	}
}



©️2020 CSDN 皮肤主题: 岁月 设计师:pinMode 返回首页