MyBatis框架教程「实践与工具类封装」

640

Web项目聚集地

图文教程,技术交流

640?

实践与工具类封装

上一篇文章我们学习了MyBatis框架的环境搭建以及对sqlsessionfactory有个大致的了解,这篇文章就要运用搭建好的环境进行增删改查并且指出一些细节。

同样我们会进行mybatis工具类的封装,把共同的生成sqlSession的代码进行提取封装成工具类,需要sqlSession直接去工具类拿就可以了。文章中我们还可以学习到一些关于日志处理的知识,初步对单元测试的使用。

640

我们的案例使用的简单的Java项目不是基于动态web项目,因为我们现在处于学习阶段,关于SSM框架的整合会在以后的文章中进行详细的讲解。

1.案例截图

640

2. User.java

 
 

注意:由于篇幅限制,我们对User属性的getter,setter和tostring方法进行省略

3. mybatis-config.xml

这是Mybatis框架的核心配置文件,其中配置了相关环境和加载映射文件,环境中确定数据源,在数据源中配置你需要链接数据库的相关信息,比如用户名、密码。映射文件就是你编写SQL的xml,通过此核心配置文件进行加载关联。

注意这里的关键点:

  • 默认的环境 ID(default="development")

  • 每个 environment 元素定义的环境 ID

  • 事务管理器的配置(type="JDBC")

  • 数据源的配置(type="POOLED")

可以对环境随意命名,但一定要保证默认的环境 ID 要只匹配其中一个环境 ID

4. TestMapper.xml

<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTDMapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.jujidi.model.User">
 <!-- 通过id返回数据 -->
 <select id="load" parameterType="integer" resultType="com.jujidi.test.User">
    select * from user where user_id=#{user_id}
 </select>
 <select id="userList" resultType="map">
   select * from user
 </select>
 <select id="count" resultType="integer">
    select count(*) from user
 </select>
 <insert useGeneratedKeys="true" keyProperty="user_id" id="add" parameterType="com.jujidi.test.User" >
    insert into user(user_name,account,password) values (#{user_name},#{account},#{password})
 </insert>
</mapper>

Mapper是映射文件,对应多个标签(可以理解为SQL),每一个标签有唯一的id用来定位。

上方的代码是此文章案例使用的配置,下面我们扩展MyBatis进行简单增删改查的mapper文件写法:

5.  映射文件写法扩展

插入:

<mapper namespace="com.jujidi.model.User">
    <insert id="insertPerson" parameterType="com.jujidi.model.User">
      INSERT INTO user(user_name,password) VALUES(#{name},#{password})
    </insert>
  </mapper>
 
  <mapper namespace="需要实现接口的全限定类名">
   <insert id="需要实现的接口里的方法名" parameterType="方法参数类型,如果是对象要写全限定类名">
    INSERT sql命令(命令里通过#{}获取对象属性)
  </insert>
  <mapper>

查询:

<!-- 通过id返回数据 -->
<select id="load" parameterType="integer" resultType="com.jujidi.test.User">
  select * from user where user_id=#{user_id}
</select>

<select id="方法名"  parameterType="方法参数类型"  resultType="方法返回值类型,全类名">
  SELECT 表里字段名 AS 结果字段名 FROM 表名 WHERE 条件
  <!--注意:结果字段名与属性名保持一致,区分大小写-->
</select>

修改:

<update id="updateUserById" parameterType="com.jujidi.test.User">  
   update user   
         set name=#{name},status=#{status}  
      where user_id=#{user_id}  
 </update>

删除:

<delete id="deleteUserById"parameterType="int">  
   delete from user  
    where user_id=#{id}  
 </delete>

关于传递参数:

<select id="load" parameterType="integer" resultType="com.jujidi.test.User">
     select * from user where user_id=#{user_id}
</select>

通过上面几行代码描述:在mybatis映射文件的配置中,有select等标签都提到了parameterType属性,parameterType为输入参数,在配置的时候,配置相应的输入参数类型即可。

parameterType有基本数据类型和复杂的数据类型配置:

1.基本数据类型,如输入参数只有一个,其数据类型可以是基本的数据类型

2.复杂数据类型:包含java实体类,map

6. 映射文件配置详解

<select id="load" parameterType="integer" resultType="com.jujidi.test.User">
   select * from user where user_id=#{user_id}
</select>
<select id="userList" resultType="map">
   select * from user
</select>

第一个select标签:此标签id为load,传入integer类型的user_id,去user表中查询此id的用户信息,把结果返回。返回值的类型为User对象。

第二个select标签:此标签id为userList,不需要参数,去user表中查询所有用户信息,进行结果反回。返回值的类型为map。

上方的两条select语句中,有一个属性是:resultType是SQL映射文件中定义返回值类型,返回值有基本类型,对象类型,List类型,Map类型等。

  • 基本类型:resultType=基本类型

  • List类型:resultType=List中元素的类型

  • Map类型 

    • 单条记录:resultType=map

    • 多条记录:resultType =Map中value的类型

代码中第一条select语句的resultType使用的对象类型,resultType直接写的对象User的全类名,而第二条select语句返回类型使用的是map,显然效果都是一样的。

7. 为什么是使用map而不是Map呢?

刚刚配置中的resultType="map",为什么是map,不是Map呢?

如果想写Map,需要写成全限定类名,即:resultType = "java.util.Map" map是java.util.Map的一个简写,还有其他的简写可以参考下方表格:

640

640

我们看下方两个语句的resultType:

<select id="load" parameterType="integer" resultType="com.jujidi.test.User">
   select * from user where user_id=#{user_id}
</select>
<select id="userList" resultType="map">
   select * from user
</select>

对于resultType属性,填写User的全类名和map类型效果都一样,还是有一些区别的。比如:如果使用User的全类名作为resultType的参数的话,我们需要保证实体类的属性名字和数据库字段的名字相同,否则的话是接不到值的。

想要实体类的属性和数据库字段不相同,我们有办法解决,可以通过更改SQL语句(别名)等方式来达到目的。

除了resultType属性外还有一个叫做:resultMap,它们俩的区别在后面的文章进行讲解。

8. MyBatisTest.java

public class MybatisTest {
public static void main(String[] args ) {
  SqlSession sqlSession = null;
  try{
      //加载核心配置文件
      InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
      //创建sqlsession工厂 -->相当于connection
      SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
      //获取sqlsession -->相当于执行sql语句对象
      sqlSession = sqlSessionFactory.openSession();
      //执行sql
     User user = sqlSession.selectOne("com.jujidi.model.User.load",1);
      System.out.println(user);
      List<Map<String,Object>> userList = sqlSession.selectList("com.jujidi.model.User.userList");
      System.out.println(userList);
      Integer count =sqlSession.selectOne("com.jujidi.model.User.count");
      System.out.println(count);
      }catch( Exception e){
     // TODO Auto-generated catch block
     e.printStackTrace();
      }finally{ 
         if(sqlSession!=null){
      sqlSession.close();
     }
   }
 }
}

上方是测试类,测试类中我们加载核心配置文件、利用核心配置文件的信息来获取sqlsession工厂,工厂生成sqlsession。然后定位映射文件Mapper中的SQL语句进行执行相应查询方法。

9. 事务的提交

测试类中执行下方的insert方法:

public class MybatisTest {
 public static void main(String[] args ) {
  SqlSession sqlSession = null;
  try{
       //加载核心配置文件
      InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
      //创建sqlsession工厂 -->相当于connection
      SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
      //获取sqlsession -->相当于执行sql语句对象
      sqlSession = sqlSessionFactory.openSession();
     User user = new User();
     user.setAccount("admin");
     user.setPassword("123");
     user.setUser_name("王久一");
     sqlSession.insert("com.jujidi.model.User.add",user);
     }catch( Exception e){
      // TODO Auto-generated catch block
      e.printStackTrace();
     }finally{ 
         if(sqlSession!=null){
       sqlSession.close();
      }
   }
  }
}

Mapper.xml中语句为:

<insert useGeneratedKeys="true" keyProperty="user_id" id="add" parameterType="com.jujidi.test.User" >
   insert into user(user_name,account,password) values (#{user_name},#{account},#{password})
</insert>

当我们执行insert方法时候,我们会发现:运行期间没有报错,但是数据库中并没有多出刚刚插入的记录。

这是因为进行了插入事务,事务并没有提交。不像以前学习的JDBC会自动提交事务。当我们利用MyBatis执行插入语句后,好像我们使用Navicat工具修改了表中的数据没有点保存一样。必须手动进行提交事务,我们对代码做出如下修改:

MybatisTest .java

public class MybatisTest {
 public static void main(String[] args ) {
   SqlSession sqlSession = null;
   try{
       //加载核心配置文件
     InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
     //创建sqlsession工厂 -->相当于connection
     SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
     //获取sqlsession -->相当于执行sql语句对象
     sqlSession = sqlSessionFactory.openSession();
     User user = new User();
     user.setAccount("admin");
     user.setPassword("123");
     user.setUser_name("王久一");
     sqlSession.insert("com.jujidi.model.User.add",user);
    sqlSession.commit();
     System.out.println(user.getUser_id());
     }catch( Exception e){
      // TODO Auto-generated catch block
      e.printStackTrace();
     }finally{
        if(sqlSession!=null){
       sqlSession.close();
      }
    }
  }
}

加上了sqlSession.commit()语句,这时候就可以成功的修改表中的数据。还有一个比较神奇的小细节:在我们还没有添加sqlSession.commit()语句时,虽然运行后没办法真正插入一条数据,但是想要插入数据的ID还是会生成的。

10. 获取ID

当我们插入了一条数据,怎么来获得新插入的数据的id?

再回到这条mapper语句:

<insert useGeneratedKeys="true" keyProperty="user_id"  id="add"  parameterType="com.jujidi.test.User" >
   insert into user(user_name,account,password) values (#{user_name},#{account},#{password})
</insert>

上方的insert标签属性添加了:

useGeneratedKeys="true" keyProperty="user_id"

 这两个属性后,执行下方的代码:

sqlSession.insert("com.jujidi.model.User.add",user);
 sqlSession.commit();
 System.out.println(user.getUser_id());

提交插入一条记录后,可以通过user.getUser_id()来获取刚插入记录的ID.

11. MyBatis工具类的封装

我们发现当使用Mybatis进行操作时,加载核心配置文件、创建sqlsession工厂等都是重复的代码,于是我们想着自己封装一个Mybatis工具类,此工具类负责返回一个sqlsession和一些关闭会话的操作。

工具类:MybatisUtil.java

public final class MybatisUtil {
 private MybatisUtil(){}
 private static final String PATH = "mybatis-config.xml";
 private static InputStream is = null;
 private static SqlSessionFactory sqlSessionFactory = null;
 static{
   try{
      //加载核心配置文件
       is = Resources.getResourceAsStream(PATH);
       //创建sqlsession工厂 -->相当于connection
       sqlSessionFactory = newSqlSessionFactoryBuilder().build(is);
       }catch(Exception e){
      e.printStackTrace();
      throw new RuntimeException("加载映射文件失败可能是你的映射文件写错了原因:"+e.getMessage());
      }
    }
    //获取sqlsession -->相当于执行sql语句对象
    public static SqlSession getSqlSession(){
     return sqlSessionFactory.openSession();
    }
    public static void closeSqlSession(SqlSession sqlSession){
     if(sqlSession!=null){
       sqlSession.close();
    }
  }
}

对于上方配置文件的关键字做出一些解释:

11.1 不可继承

final:不可以被继承

final:修饰一个变量path,变成常量不可以修改其值

11.2 不可实例化

private MybatisUtil(){}

工具类类名是:MybatisUtil。构造方法是用public修饰,但是上方使用了private。我们知道构造方法是用来实例化对象的,private来修饰说明本类不能被实例化。

11.3 初始化

static{
   try{
     ...
    }catch(IOException e){
      ...
    }
   }

上方代码:类加载就会加载静态代码块的代码 ,类初始化的时候就加载配置文件获取工厂。

11.4异常处理

catch(IOException e){
  e.printStackTrace();
  throw new RuntimeException("加载映射文件失败可能是你的映射文件写错了原因:"+e.getMessage());
}

对于catch到的异常 "加载映射文件失败,可能是映射文件写错了"要解释一下:

1. mybatis-config 配置了映射文件,映射文件配置出错,加载核心配置文件的时候也会报错 

2. 为什么不提示mybatis-config.xml写错了呢?因为相应的环境参数配置一次就完毕,就是有错误调试成功以后很少会改动xml,而映射文件是常常需要我们编写修改的,所以抛出这样的提示更利于报错的时候准确找到错误。

12.单元测试

我们知道main()方法只能有一个,如果都在main方法里面进行测试代码,就需要注释掉测试完毕的方法,仅仅运行自己当前需要测试的功能方法,这样显得杂乱无章,所以我们学习一下单元测试,不仅对以后的学习有帮助,在工作中也是经常用到。

12.1 新建java工程

添加JUnit相关Jar包

右键项目:Build Path->Configure Builde Path->Add Library->JUnit->Next->Finish

Test01 .java

public class Test01 {
   @Test
  public void test01(){
    System.out.println("王久一");
  }

  @Test
  public void test02(){
    System.out.println("小小詹");
  }

  @Test
  public void test03(){
    System.out.println("老邓头");
  }
}

12.2 测试运行

对于上方代码:我们测试test01()方法,只需要选中test01:

640

右键->Run as->JUnit Test:

控制台便会打印出:王久一   

以此类推,我们分别运行test02和test03方法,也会有相同的效果。

接下来修改代码:

public class Test01 {
  @Before
  public void before(){
    System.out.println("Web项目聚集地before");
  }

  @After
  public void after(){
   System.out.println("Web项目聚集地after");
  }

   @Test
  public void test01(){
    System.out.println("王久一");
  }

  @Test
  public void test02(){
    System.out.println("小小詹");
  }

  @Test
  public void test03(){
    System.out.println("老邓头");
  }
}

12.3 再次运行

测试test01()方法,控制台打印为:

640

添加@Before和 @After注解后,产生的效果可想而知。

12.4 一起运行

如果不单个运行,一起运行是什么效果呢? 

640

13.  log4j日志包

最后方便开发调试,我们需要增加日志功能:

导入log4j包

在classpath下添加log4j.properties文件:

# Global loggingconfiguration
log4j.rootLogger=ERROR,stdout
# 注意log4j.logger后面是需要日志处理mapper的namespace名称
log4j.logger.com.jujidi.model.User=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p[%t]-%m%n

通过第四行的配置和映射文件关联,在执行相关联mapper中的SQL就会在控制台打印出日志信息。

重要说明:实际开发中是不会使用Mybatis工具类来进行开发的,而是SSM框架整合后,通过接口代理的方式来实现对数据库的操纵。

为了使初学者对Mybatis框架有一个独立且系统的认识,所以采用这种系统的教学方式,而不是一开始就是整合。我们会在学习过程中逐渐拓展,最终达到实际开发所需要的本领。

如果您觉得此平台教程不错的话,欢迎推荐给自己的朋友!

1. 

2.

3. 

4. 

640

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值