设为首页 收藏本站
查看: 873|回复: 0

[经验分享] mybatis系列二:单表CRUD

[复制链接]

尚未签到

发表于 2016-11-26 09:22:54 | 显示全部楼层 |阅读模式
  单表的CRUD。  C:Create,创建;R:Retrieve,读取;U:Update,更新;D,Delete,删除。
  1. 首先配置映射文件User.xml
    DSC0000.jpg

<?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.alex.app.entity.User">
<select id="selectUser" parameterType="int" resultType="com.alex.app.entity.User">
select * from t_user where id = #{id}
</select>
<insert id="insertUser" parameterType="com.alex.app.entity.User">
insert into t_user(username,password)
values(#{username},#{password})
</insert>
<update id="updateUser" parameterType="com.alex.app.entity.User">
update t_user set username=#{username},password=#{password}
where id = #{id}
</update>
<delete id="deleteUser" parameterType="int">
delete from t_user where id = #{id}
</delete>
</mapper>
  2. 先提供一个工具类,方便测试
    DSC0001.jpg


package com.alex.app.util;
import java.io.IOException;
import java.io.InputStream;
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 MyBatisUtil {
private MyBatisUtil() {
}
private static SqlSessionFactory factory;
private static String configFile = "mybatis-config.xml";
static{
InputStream in;
try {
//  加载总配置文件
in = Resources.getResourceAsStream(configFile);
// 创建SqlSessionFactory
factory = new SqlSessionFactoryBuilder().build(in);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取SqlSession,并关闭自动提交,打开事务。
* 通俗点说就是将自动提交事务,改为手动提交
* @return
*/
public static SqlSession openSession(){
return factory.openSession();
}
/**
* 关闭session
* @param session
*/
public static void coloseSession(SqlSession session){
if(session != null){
session.close();
}
}
}

    SqlSession创建的时候,会关闭自动提交,打开事务。我们扫一眼SqlSessionFactory的openSessoin方法的源码就知道了。

  以下源码分析不是重点,可以略过
  eclipse中,使用 maven构建的项目要把源码一并下载下来,右击pom.xml选择Run As-->Maven Build..,在对话框Goals中输入命令dependency:sources,点Run,相关maven的插件和源码就都下载下来。
    DSC0002.jpg

  源码已经关联上,图标上有了个文本的标识
   DSC0003.jpg
 

  SqlSessionFactory是个接口,这里调用到的是DefaultSqlSessionFactory实现类的openSessoin方法。

public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
 我们看到第4个参数的值就是false。往里看代码直到JdbcTransaction类中,构造方法有
  public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
dataSource = ds;
level = desiredLevel;
autoCommmit = desiredAutoCommit;
}
 flase这个值会传递给JdbcTransaction构造方法的desiredAutoCommit,设置了autoCommmit 这个值为false。  那么肯定有地方调用了这个构造方法,在哪里呢,是在SqlSessoin调用insert/update/delete方法的时候

  public int insert(String statement, Object parameter) {
return update(statement, parameter);
}

 调用了update(statement, parameter)
  public int update(String statement, Object parameter) {
try {
dirty = true;
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
 继续往里跟executor.update(ms, wrapCollection(parameter));直到BatchExecutor类的doUpdate方法
  public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
//.....省略这些代码,节省篇幅
if (sql.equals(currentSql) && ms.equals(currentStatement)) {
//.....省略这些代码,节省篇幅
} else {
Connection connection = getConnection(ms.getStatementLog());
stmt = handler.prepare(connection);
//.....省略这些代码,节省篇幅
}
//.....省略这些代码,节省篇幅
}
 其中有一句代码是Connection connection = getConnection(ms.getStatementLog());
  protected Connection getConnection(Log statementLog) throws SQLException {
Connection connection = transaction.getConnection();
if (statementLog.isDebugEnabled()) {
return ConnectionLogger.newInstance(connection, statementLog, queryStack);
} else {
return connection;
}
}
  Connection connection = transaction.getConnection();transaction对象这里是JdbcTransaction对象
  public Connection getConnection() throws SQLException {
if (connection == null) {
openConnection();
}
return connection;
}

 openConnection();
  protected void openConnection() throws SQLException {
// 省略...
setDesiredAutoCommit(autoCommmit);
}
 
  protected void setDesiredAutoCommit(boolean desiredAutoCommit) {
try {
if (connection.getAutoCommit() != desiredAutoCommit) {
//.....
connection.setAutoCommit(desiredAutoCommit);
}
} catch (SQLException e) {
// ....
}
}
 connection.setAutoCommit(desiredAutoCommit);desiredAutoCommit参数的值就是在SqlSession调用openSessoin()方法的时候,第4个参数值 false

public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
上面的源分析码可以无视,不是重点  3. 编写UserTest测试类。
    DSC0004.jpg

package com.alex.app.test;
import org.apache.ibatis.session.SqlSession;
import org.junit.Assert;
import org.junit.Test;
import com.alex.app.entity.User;
import com.alex.app.util.MyBatisUtil;
public class UserTest {
/**
* C,Create 创建
*/
@Test
public void testInsertUser() {
SqlSession session = null;
try {
// 获取SqlSession
session = MyBatisUtil.openSession();
// 准备要添加的数据
User user = new User();
user.setUsername("belongtou");
user.setPassword("9988");
/*insert()方法说明
* 第一个参数,就是User.xml的namespace属性  + "." +  insert标签的id属性
* 我们看到User.xml的namespace属性正好与我们的实体User的完整类名一致
* 所以我们可以使用反射的方式取到这个完整的类名,然再后 + "." +  insert标签的id属性,
* 一长串的字符写起来很容易出错的。我们说约定优与配置:::
* */
session.insert(User.class.getName()+".insertUser",user);
/* 需要手动提交事务
* mybaits的事务在创建SqlSessoin时,自动将作了一个操作:Connection.setAutoCommint(false),将事务设置为非自动提交。
*/
session.commit();
} catch (Exception e) {
e.printStackTrace();
// 异常回滚
session.rollback();
}finally{
// 关闭SqlSession
MyBatisUtil.coloseSession(session);
}
}
/**
* R,Retrieve 读取
*/
@Test
public void testSelectUser() {
SqlSession session = null;
try {
session = MyBatisUtil.openSession();
User user = (User)session.selectOne(User.class.getName()+".selectUser",2);
// 断言 user不为空
Assert.assertNotNull(user);
// 断言user对象的Id就是我们刚上面所查询到的ID值 2
// assertEquals第一个参数是预期值,第二个参数是实际
Assert.assertEquals(user.getId(), 2);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* U, Update 更新
*/
@Test
public void testUpdateUser() {
SqlSession session = null;
try {
session = MyBatisUtil.openSession();
User user = (User)session.selectOne(User.class.getName()+".selectUser", 1);
Assert.assertNotNull(user);//断言user对象不为null
user.setUsername("Nunu");
user.setPassword("7788");
session.update(User.class.getName()+".updateUser", user);
session.commit();
User user2 = (User)session.selectOne(User.class.getName()+".selectUser", 1);
Assert.assertNotNull(user2);
//断言,user2所查询到的值,与我们上面更新时(更新user对象)所设置的值是否一致。一致则测试通过
Assert.assertEquals(user2.getUsername(), "Nunu");
Assert.assertEquals(user2.getPassword(), "7788");
} catch (Exception e) {
e.printStackTrace();
session.rollback();
}finally{
MyBatisUtil.coloseSession(session);
}
}
/**
* D ,Delete 删除
*/
@Test
public void testDeleteUser() {
SqlSession session = null;
try {
session = MyBatisUtil.openSession();
session.delete(User.class.getName()+".deleteUser", 3);
session.commit();
} catch (Exception e) {
e.printStackTrace();
session.rollback();
}finally{
MyBatisUtil.coloseSession(session);
}
}
}

  注意,SqlSession在创建的时候,MyBatis把事务自动设置为了false,就是JDBC规范的Connection.setAutoCommit(false);事务不会自动提交。再做URD的时候,需要调用SqlSession的commint() 方法提交。
  4. 映射文件问题
  现在我们映射文件有很多重复主要是parameterType="com.alex.app.entity.User"  resultType="com.alex.app.entity.User" 这里,都是重复的。
  我们可以在mybatis-config.xml配置文件中properties标签和environments之前,使用typeAlias 标签配置一个别名

<?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 resource="jdbc.properties" />
<typeAliases>
<typeAlias type="com.alex.app.entity.User" alias="User"/>
</typeAliases>
<environments default="development">
<!--  省略部分配置 -->
</environments>
<!-- 映射文件 -->
<mappers>
<mapper resource="com/alex/app/entity/User.xml"/>
</mappers>
</configuration>
  那么在映射文件中,就可以使用这个别名来定义这些属性 parameterType="User"  resultType="User"

<?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.alex.app.entity.User">
<select id="selectUser" parameterType="int" resultType="User">
select * from t_user where id = #{id}
</select>
<insert id="insertUser" parameterType="User">
insert into t_user(username,password)
values(#{username},#{password})
</insert>
<update id="updateUser" parameterType="User">
update t_user set username=#{username},password=#{password}
where id = #{id}
</update>
<delete id="deleteUser" parameterType="int">
delete from t_user where id = #{id}
</delete>
</mapper>
  单元的测试断言部分不用纠结,可以直接去数据库中查看。或者最笨的方式直接把信息打印到控制台上查看。
  另外还有几个问题,就是在执行CRUD操作的时候,会破坏数据库中的数据;每个单元测都是独立的,不依赖与其它单元测试,假如我先执行一个删除动作,删除Id 为2的数据,之后执行了查询动作,查询ID为2的数据,这时候可能会出错。
  单元测试是为了测试我们的功能片断是否正常,每个分支是否覆盖到,一些代码的边界是否存在的问题等等,这里不纠结它了,后面我们再研究。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-305721-1-1.html 上篇帖子: mybatis 插入null 时需要指定jdbcType 下篇帖子: SpringMVC+mybatis 实现easyui中tree
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表