2.4 实例
这里做一个实例,它可以使我们熟悉 MyBatis 主要组件的用法。我们需要满足 MyBatis 各个组件的生命周期。首先需要生成 SqlSessionFacotry 单例,然后让它生成 SqlSession,进而拿到映射器中来完成我们的业务逻辑。
确定文件所需要放置的路径,以便在上下文中读取配置文件,如图 2-7 所示。
图 2-7 实例文件路径
各个实例文件的作用,如表 2-1 所示。
表 2-1 实例文件的作用
首先,提供 log4j 的配置文件,如代码清单 2-11 所示。它为我们打出 MyBatis 的运行轨迹,给我们调试 MyBatis 应用带来了极大的帮助。
代码清单 2-11:log4j.properties
log4j.rootLogger=DEBUG , stdout log4j.logger.org.mybatis=DEBUG log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p %d %C: %m%n
其次,构建 SessionFactory,我们需要配置文件,如代码清单 2-12 所示。
代码清单 2-12: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> <typeAliases> <typeAlias alias="role" type="com.learn.chapter2.po.Role"/> </typeAliases> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"> <property name="autoCommit" value="false"/> </transactionManager> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/> <property name="username" value="root"/> <property name="password" value="learn"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com\learn\chapter2\mapper\roleMapper.xml"/> </mappers> </configuration>
最后,构建 SqlSessionFactory,并且给出创建 SqlSession 的方法,这里我们利用配置文件 mybatis-config.xml 完成 SqlSessionFactory 的构建。这里和上面有些变化,我们不妨先看看代码如何现实,如代码清单 2-13 所示。
代码清单 2-13:SqlSessionFactoryUtil.java
package com.learn.chapter2.util; import java.io.IOException; import java.io.InputStream; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class SqlSessionFactoryUtil { //SqlSessionFactory 对象 private static SqlSessionFactory sqlSessionFactory = null; //类线程锁 private static final Class CLASS_LOCK = SqlSessionFactoryUtil.class; /** * 私有化构造参数 */ private SqlSessionFactoryUtil() {} /** * 构建 SqlSessionFactory */ public static SqlSessionFactory initSqlSessionFactory() { String resource = "mybatis-config.xml"; InputStream inputStream = null; try { inputStream = Resources.getResourceAsStream(resource); } catch (IOException ex) { Logger.getLogger(SqlSessionFactoryUtil.class.getName()).log(Level.SEVERE, null, ex); } synchronized(CLASS_LOCK) { if (sqlSessionFactory == null) { sqlSessionFactory=new SqlSessionFactoryBuilder().build (input Stream); } } return sqlSessionFactory; } /** * 打开 SqlSession */ public static SqlSession openSqlSession() { if (sqlSessionFactory == null) { initSqlSessionFactory(); } return sqlSessionFactory.openSession(); } }
解释一下代码的含义,正如生命周期描述的一样,我们希望 SqlSessionFactory 对于一个数据库而言只有一个实例,于是我们希望它是单例。现在我们学习一下代码如何实现单例模式。
构建 SessionFactory 单例是通过方法 initSqlSessionFactory 实现的。首先,将构造方法设置为私有(private),其目的是避免使用者使用 new 的方式去创建多个对象。然后,我们使用 synchronized 对 SqlSessionFactoryUtil 类加锁,其目的是避免在多线程环境(MyBatis 多用于多线程环境,比如 Web 服务器,Socket 请求等)中,多次初始化造成对象的不唯一。
某一个对象在应用中承担唯一责任的时候使用单例模式,而本例中 SqlSessionFactory 的唯一责任就是为我们创建 SqlSession,所以采用单例模式。单例模式的好处在于可以重复使用这个唯一对象,而对象在内存中读取和运行速度都比较快,同时节约内存。我们的办法往往是把构造方法私有化,并给一个静态(static)方法,让其返回唯一单例,而在多线程环境初始化单例,往往需要加线程锁以避免类对象被多次初始化,正如本例一样。
我们还实现了 openSqlSession 方法,利用构建好的 SqlSessionFactory 创建 SqlSession,为将来所用奠定基础。
这里我们要给一个 POJO 类 - Role.java,如代码清单 2-14 所示,它就是一个很普通的 JavaBean。
代码清单 2-14:Role.java
package com.learn.chapter2.po; public class Role { private Long id; private String roleName; private String note; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getRoleName() { return roleName; } public void setRoleName(String roleName) { this.roleName = roleName; } public String getNote() { return note; } public void setNote(String note) { this.note = note; } }
我们还需要一个映射器的描述,让我们编写 XML 映射文件,如代码清单 2-15 所示。
代码清单 2-15:RoleMapper.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="com.learn.chapter2.mapper.RoleMapper"> <select id="getRole" parameterType="long" resultType="role"> select id, role_name as roleName, note from t_role where id = #{id} </select> <insert id="insertRole" parameterType="role"> insert into t_role(role_name, note) values (#{roleName}, #{note}) </insert> <delete id="deleteRole" parameterType="long"> delete from t_role where id = #{id} </delete> </mapper>
这里我们定义了 3 条 SQL,它们的作用有 3 个。
查询一个角色对象。
插入角色。
删除角色表的数据。
这时候需要定义一个接口,注意接口的方法要和 XML 映射文件的 id 保持一致,于是得出下面的接口,如代码清单 2-16 所示。
代码清单 2-16:RoleMapper.java
package com.learn.chapter2.mapper; import com.learn.chapter2.po.Role; public interface RoleMapper { public Role getRole(Long id); public int deleteRole(Long id); public int insertRole(Role role); }
为此我们已经构建好 SqlSessionFactory,同时也提供了创建 SqlSession 的方法和映射器,完成了对应的 3 个方法。现在我们可以利用这些东西完成下面两个任务了。
(1)插入一个角色(Role)对象。
(2)删除一个编号为 1L 的角色对象。
这里我们使用 Chapter2Main.java 类完成我们需要完成的任务,如代码清单 2-17 所示。
代码清单 2-17:Chapter2Main.java
package com.learn.chapter2.main; import java.io.IOException; import java.io.InputStream; import org.apache.ibatis.datasource.pooled.PooledDataSource; import org.apache.ibatis.io.Resources; import org.apache.ibatis.mapping.Environment; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.apache.ibatis.transaction.TransactionFactory; import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; import com.learn.chapter2.mapper.RoleMapper; import com.learn.chapter2.po.Role; import com.learn.chapter2.util.SqlSessionFactoryUtil; public class Chapter2Main { public static void main(String[] args) throws IOException { SqlSession sqlSession = null; try { sqlSession = SqlSessionFactoryUtil.openSqlSession(); RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class); Role role = new Role(); role.setRoleName("testName"); role.setNote("testNote"); roleMapper.insertRole(role); roleMapper.deleteRole(1L); sqlSession.commit(); } catch(Exception ex) { System.err.println(ex.getMessage()); sqlSession.rollback(); } finally { if (sqlSession != null) { sqlSession.close(); } } } }
至此我们的代码完成了,让我们用 Java Application 的形式运行一下 Chapter2Main.java。我们可以看到如下结果。
...... DEBUG 2016-02-01 14:48:10,528 org.apache.ibatis.transaction.jdbc. JdbcTransaction:Setting autocommit to false on JDBC Connection[com. mysql.jdbc.JDBC4Connection@7e0b0338] DEBUG 2016-02-01 14:48:10,531 org.apache.ibatis.logging.jdbc. BaseJdbcLogger: ==> Preparing: insert into t_role(role_name, note) values (?, ?) DEBUG 2016-02-01 14:48:10,563 org.apache.ibatis.logging.jdbc.Base JdbcLogger: ==> Parameters: testName(String), testNote(String) DEBUG 2016-02-01 14:48:10,564 org.apache.ibatis.logging.jdbc.Base JdbcLogger:<==Updates:1 DEBUG 2016-02-01 14:48:10,564 org.apache.ibatis.logging.jdbc. Base JdbcLogger: ==> Preparing: delete from t_role where id = ? DEBUG 2016-02-01 14:48:10,565 org.apache.ibatis.logging.jdbc. Base JdbcLogger:==> Parameters: 1(Long) DEBUG 2016-02-01 14:48:10,566 org.apache.ibatis.logging.jdbc.BaseJdbc Logger:<==Updates:1 DEBUG 2016-02-01 14:48:10,566 org.apache.ibatis.transaction.jdbc. JdbcTransaction: Committing JDBC Connection [com.mysql.jdbc.JDBC4Connec tion@7e0b0338] ......
这样 Log4j 为我们打印出了 MyBatis 的运行轨迹,最为重要的是它为我们打印出了运行的 SQL 和参数。在调试中这些信息是十分重要的,如果发生异常我们将可以找到问题的所在,也能找到插入和删除角色的过程,运行完全成功。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论