MyBatis学习(一)---配置文件,Mapper接口和动态SQL

MyBatis

  MyBatis官方学习网站

         http://www.mybatis.org/mybatis-3/zh/index.html

  为什么需要MyBatis?

  Jdbc操作数据库的不足之处

1、需要通过硬编码的方式建立到数据库的连接

2、需要通过硬编码的方式来创建PreparedStatment对象

3、频繁的关闭连接、建立连接,导致系统的性能会下降

  MyBatis

  MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。Mybatis框架封装了jdbc的一个持久层的框架,它和Hibernate都属于ORM框架,Hibernate是一个完全的orm框架,Mybatis不是一个完全的orm框架,不需要关注数据库连接的建立、Statement或PreparedStatement的创建,更多的去关注sql语句本身。

  通过下面的项目来了解MyBatis

  项目目录结构

本项目使用的Oracle数据库,项目对象的表为user_tab

src目录下是一个是MyBatis的配置文件

<?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>
    <!-- 指定了默认的环境为development -->
  <environments default="development">
      <!-- 指出了环境的唯一标识 -->
    <environment id="development">
        <!-- 指出了事务管理器 -->
      <transactionManager type="JDBC"/>
      <!-- 指出了连接池,并指出了连接数据库的驱动,url,用户名,密码 -->
      <dataSource type="POOLED">
        <property name="driver" value="oracle.jdbc.driver.OracleDriver"/>
        <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"/>
        <property name="username" value="scott"/>
        <property name="password" value="itcast"/>
      </dataSource>
    </environment>
  </environments>
  <!-- 注册映射文件,路径中.都用/代替 -->
  <mappers>
    <mapper resource="com/ghq/model/dao/impl/UserDaoImpl.xml"/>
  </mappers>
</configuration>

 

表所对应的实体类为User.java

package com.ghq.model.entity;

import java.util.Date;

public class User {
    private int id;
    private String username;
    private String userpass;
    private Date birthday;
    private int height;
    private String gender;
    
    public User(int id, String username, String userpass, Date birthday,
            int height, String gender) {
        this.id = id;
        this.username = username;
        this.userpass = userpass;
        this.birthday = birthday;
        this.height = height;
        this.gender = gender;
    }
    public User(String username, String userpass, Date birthday, int height,
            String gender) {
        this.username = username;
        this.userpass = userpass;
        this.birthday = birthday;
        this.height = height;
        this.gender = gender;
    }
    public User() {
        
    }
    //省略setter/getter方法
    @Override
    public String toString() {
        return "User [id=" + id + ", username=" + username + ", userpass="
                + userpass + ", birthday=" + birthday + ", height=" + height
                + ", gender=" + gender + "]";
    }
    
}

 

 工具类MyBatisDb.java

  主要的功能是获取获取SqlSessionFactory以及SqlSession的对象,SqlSession中具有对数据表增删改查的方法。

package com.ghq.model.utils;

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 MybatisDb {
    private static String config = "mybatis-config.xml";
    private static SqlSessionFactory sqlSessionFac;
    
    static{
        try {
            //读取配置文件
            InputStream inputstream = Resources.getResourceAsStream(config);
            //获取SqlSessionFactory对象
            sqlSessionFac = new SqlSessionFactoryBuilder().build(inputstream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    //获取SqlSession对象,并且开启了事务
    public static SqlSession getSession(){
        return sqlSessionFac.openSession();
    }
    
}

 

 

UserDao.java 是一个接口,其中的内容主要是实现用户的增删改查功能

package com.ghq.model.dao;

import java.util.List;
import com.ghq.model.entity.User;

public interface UserDao {
    //根据id查询用户
    User getUserById(int id);
    //根据模糊姓名和性别查询
    List<User> getUserBynameAndGender(User u);
    //新增用户
    boolean addUser(User u);
    //修改用户
    boolean updateUser(User u);
    //删除用户
    boolean delUser(int id);
}

 

 

UserDaoImpl.java是UserDao的实现类

package com.ghq.model.dao.impl;

import java.util.List;

import org.apache.ibatis.session.SqlSession;

import com.ghq.model.dao.UserDao;
import com.ghq.model.entity.User;
import com.ghq.model.utils.MybatisDb;

public class UserDaoImpl implements UserDao {
    //通过id获取用户的方法
    @Override
    public User getUserById(int id) {
        //获得SQLSession对象
        SqlSession session = MybatisDb.getSession();
        //执行com.ghq.model.dao.impl.UserDaoImpl.getUserById标识的SQL语句,在执行前为占位参数赋值
        User u = session.selectOne("com.ghq.model.dao.impl.UserDaoImpl.getUserById", id);
        session.close();
        return u;
    }

    //根据模糊姓名和性别查询
    @Override
    public List<User> getUserBynameAndGender(User u) {
        //获得SQLSession对象
        SqlSession session = MybatisDb.getSession();
        List<User> ulist = session.selectList("com.ghq.model.dao.impl.UserDaoImpl.getUserBynameAndGender", u);
        session.close();
        return ulist;
    }

    //新增用户
    @Override
    public boolean addUser(User u) {
        SqlSession session = MybatisDb.getSession();
        int row = session.insert("com.ghq.model.dao.impl.UserDaoImpl.addUser", u);
        session.commit();
        session.close();
        if (row > 0) {
            return true;
        }
        return false;
    }

    //修改用户
    @Override
    public boolean updateUser(User u) {
        SqlSession session = MybatisDb.getSession();
        int row = session.update("com.ghq.model.dao.impl.UserDaoImpl.updateUser", u);
        session.commit();
        session.close();
        if (row > 0) {
            return true;
        }
        return false;
    }

    //删除用户
    @Override
    public boolean delUser(int id) {
        SqlSession session = MybatisDb.getSession();
        int row = session.delete("com.ghq.model.dao.impl.UserDaoImpl.delUser", id);
        session.commit();
        session.close();
        if (row > 0) {
            return true;
        }
        return false;
    }

}

 

 

要想实现对数据库的操作,必须配置sql的映射文件UserdaoImpl.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">
  
<!-- namespace不允许重复,用于区分同名的SQL语句标识 -->
<mapper namespace="com.ghq.model.dao.impl.UserDaoImpl">
    <!--  映射文件中的SQL语句没有分号
                #{}相当于占位符? #{}中名字标识输入参数的名字,如果输入参数是简单类型,则#{}中参数名任意
                parameterType指出了输入参数类型之外的类型
                resultType是结果类型,即返回的记录中单条记录的类型
     -->
  <select id="getUserById" parameterType="int" resultType="com.ghq.model.entity.User">
    select * from user_tab where id = #{id}
  </select>
  <!-- 输入参数类型不是简单类型,#{}中的输入参数的名字不能任意,参数类型是自定义的实体类型,#{}中使用的是属性名,模糊查询不使用#{},而使用${}  #{}两端没有单引号 -->
  <select id="getUserBynameAndGender" parameterType="com.ghq.model.entity.User" resultType="com.ghq.model.entity.User">
    select * from user_tab where username like '%${username}%' and gender = #{gender}
  </select>
  
  <insert id="addUser" parameterType="com.ghq.model.entity.User" >
      <! -- 新增用户中,用户id是通过序列来实现自动增长,所以需在数据库中创建user_tb_seq序列,然后通过select语句查询出下一个序列值,封装到标志属性中。order指出了查询是否在新增之前,是的话为BEFORE,否则为AFTER,resultType指出了查询的数据的类型,不能省略 -->
      <selectKey keyProperty="id" order="BEFORE" resultType="int">
          select user_tb_seq.nextval from dual
      </selectKey>
      insert into user_tab (id,username,userpass,birthday,height,gender) values 
      (#{id},#{username},#{userpass},#{birthday},#{height},#{gender})
  </insert>
  
  <update id="updateUser" parameterType="com.ghq.model.entity.User">
      update user_tab set username = #{username},userpass = #{userpass},birthday = #{birthday},
      height = #{height},gender = #{gender} where id = #{id}
  </update>
  
  <delete id="delUser" parameterType="int">
      delete from user_tab where id = #{id}
  </delete>
</mapper>

 

 

使用JUnit4进行单元测试testmybatis.java

package com.ghq.test;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.junit.Test;

import com.ghq.model.dao.UserDao;
import com.ghq.model.dao.impl.UserDaoImpl;
import com.ghq.model.entity.User;

public class testmybatis {
    @Test
    public void testgetUserbyID(){
        UserDao userdao = new UserDaoImpl();
        User u = userdao.getUserById(7);
        System.out.println(u);
    }
    
    @Test
    public void testgetUserbynameAndGender(){
        UserDao userdao = new UserDaoImpl();
        User user = new User();
        user.setUsername("张");
        user.setGender("女");
        List<User> ulist = userdao.getUserBynameAndGender(user);
        for (User uu : ulist) {
            System.out.println(uu);
        }        
    }
    
    @Test
    public void testaddUser(){
        UserDao userdao = new UserDaoImpl();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String str = "1990-12-12";
        Date d = null;
        try {
            d = dateFormat.parse(str);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        
        User user = new User("张三","zs",d,160,"女");
        boolean flag = userdao.addUser(user);
        if (flag) {
            System.out.println("插入成功");
        }else{
            System.out.println("插入失败");
        }                
    }
    
    @Test
    public void testupdateUser(){
        UserDao userdao = new UserDaoImpl();
        User user = new User(1,"李四 ","ls",new Date(),170,"男");
        boolean flag = userdao.updateUser(user);
        if (flag) {
            System.out.println("修改成功");
        }else{
            System.out.println("修改失败");
        }                
    }
    
    @Test
    public void testdelUser(){
        UserDao userdao = new UserDaoImpl();
        boolean flag = userdao.delUser(1);
        if (flag) {
            System.out.println("删除成功");
        }else{
            System.out.println("删除失败");
        }   
    }
}

 

 

Mapper接口

  MyBatis的项目中,可以没有dao的实现类

  Mybatis 提供了 Mapper接口的代理对象,在执行 Mapper接口方法时,实际执行的是Mybatis的代理对象,代理对象在 invoke 方法内获取 Mapper接口类全名+方法全名 作为statement的ID,然后通过ID去Statement匹配注册的SQL,然后使用 SqlSession 执行这个 SQL。

  实现这样的功能前提是映射文件和接口主文件名相同,且在同一个包下,映射文件的命名空间是接口的全限定名。

 

在mybatis-config.xml配置文件中

 

  1、注册映射文件时,若映射文件过多,推荐使用批量注册映射文件。

  批量注册映射文件的前提是:接口的主文件名要和相应映射文件名一致,而且映射文件中的namespace是接口的全限定名,接口和映射文件在同一个包下

<!-- 注册映射文件(批量注册映射文件,注册com.ghq.model.dao下的所有配置文件) -->
  <mappers>
    <package name="com.ghq.model.dao"/>
  </mappers>

  2、在配置文件中定义别名,可以在映射文件中使用别名。

<!-- 在配置文件中定义别名,可以在映射文件中使用别名 -->
    <typeAliases>
        <!-- 一次定义一个别名 -->
        <!-- <typeAlias type="com.ghq.model.entity.User" alias="user"/> -->
        <!-- 为该包下的实体类定义别名 -->
        <package name="com.ghq.model.entity"/>
    </typeAliases>

 

   定义别名后,可以在resultType或paramterType中使用user

  3、可以将连接数据库的驱动,url,用户名和密码存放在properties文件中。

db.properties文件中的配置

db.driver=oracle.jdbc.driver.OracleDriver
db.url=jdbc:oracle:thin:@127.0.0.1:1521:orcl
db.username=scott
db.password=itcast
<!-- 加载db.properties文件 -->
<properties resource="db.properties"></properties>

<environments default="development">
     <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${db.driver}"/>
        <property name="url" value="${db.url}"/>
        <property name="username" value="${db.username}"/>
        <property name="password" value="${db.password}"/>
      </dataSource>
    </environment>
  </environments>

 

 

以根据id查询用户为例:

UserDao中的代码

public interface UserDao {
    //根据id查询用户
    User getUserById(int id);
}

UserDao的映射文件UserDao.xml

<mapper namespace="com.ghq.model.dao.UserDao">
  <select id="getUserById" parameterType="int" resultType="user">
    select * from user_tab where id = #{id}
  </select>
</mapper>

单元测试的代码

public class testmybatis {
    @Test
    public void testgetUserbyID(){
        SqlSession session = MybatisDb.getSession();
        UserDao userdao = session.getMapper(UserDao.class);
        User u = userdao.getUserById(1);
        System.out.println(u);
    }
}

 

 

动态sql语句

动态sql语句涉及的元素

         1、where

         where元素默认去除第一个and,如果参数输入不合法,则会删掉where子句

         2、if

         对输入参数进行条件判断,if标签中test属性中的不存在&&,使用and代替

         3、foreach

         用于产生一个集合

工具类Uservo.java

package com.ghq.model.entity;

import java.util.List;

public class UserVo {
    private List<Integer> idlist;

    public List<Integer> getIdlist() {
        return idlist;
    }

    public void setIdlist(List<Integer> idlist) {
        this.idlist = idlist;
    }    
}

UserDao.java

//根据模糊姓名和性别查询
List<User> getUserBynameAndGender(Map<String,Object> m);
//查询一个主键范围的用户列表
public List<User> getUsersWithIdList(UserVo vo);

UserDao.xml

<select id="getUserBynameAndGender" parameterType="java.util.Map" resultType="user">
    select * from user_tab 
    <!-- where 标签默认会去除第一个and,若输入参数是null,则删除where条件 -->
    <where>
        <if test="username != null and username != ''">
            and username like '%${username}%'
        </if>
        <if test="gender !=null and gender !=''">
            and gender = #{gender}
        </if>
    </where>
  </select>

<select id="getUsersWithIdList" parameterType="UserVo" resultType="user">
      select * from user_tab
      <where>
          <if test="idlist !=null">
              and id in 
              <foreach collection="idlist" item="id" open="(" close=")" separator=",">
                  #{id}
              </foreach>
          </if>
      </where>
  </select>

单元测试

public class testmybatis {
    @Test
    public void testgetUserbynameAndGender(){
        SqlSession session = MybatisDb.getSession();
        UserDao userdao = session.getMapper(UserDao.class);
        Map<String,Object> user = new HashMap<String,Object>();
        user.put("username", "张");
        user.put("gender", "女");
        List<User> ulist = userdao.getUserBynameAndGender(user);
        for (User uu : ulist) {
            System.out.println(uu);
        }
        
    }

    //批量查询id为1,2,3的用户
    @Test
    public void testgetUsersWithIdList(){
        SqlSession session = MybatisDb.getSession();
        UserDao userdao = session.getMapper(UserDao.class);
        
        UserVo vo = new UserVo();
        List<Integer> idlist = new ArrayList<Integer>();
        idlist.add(1);
        idlist.add(2);
        idlist.add(3);
        vo.setIdlist(idlist);
        List<User> list = userdao.getUsersWithIdList(vo);
        for (User user : list) {
            System.out.println(user);
        }    
    }
}

select元素中resultMap属性

  用于解决查询数据表时,查询出的列名和实体的属性名不一致,该属性值要和

  resultMap元素的id一致,该resultMap元素就来完成查询出的列名和实体的属性名的映射,如果查询出的列名和实体的属性名一致,select元素使用resultType就可以,不需要使用resultMap属性。

 

  

posted @ 2018-01-20 23:17  Mipha  阅读(1954)  评论(0编辑  收藏  举报