Mybatis之mapper接口开发

(一)需求,为什么要使用接口开发?

  1.  在测试用例中,在调用session的方法的时候,都会传入要调用的SQL的namespace+id名称,这不是必须的。可以只传入id即可。但是,如果在mybatis的环境中有多个相同id的映射名称,就会报错。所以,一般情况下,调用方法最好还是使用namespace+id。
  2. 但是,namespace+id的使用方式很容易报错,因为是string类型的,没有检查。所以,mybatis提供了一种非常好的设计方式来避免这种问题,即Mapper接口。

   接口开发的规范namespace的值=接口的包名+接口的类名

  注意:

  1、 包名 + 类名 = XXXMapper.xml中namespace的值

  2、 接口中方法名 =  mapper.xml中 具体的SQL语句定义的id值

  3、 方法的返回值和参数要和映射文件中一致(当数据库的字段名和对象的属性名一致时,可以用简单属性resultType。但是当数据库中的字段名称和对象中的属性名称不一致时,就需要resultMap                  属性。

   /*
     <select id="all" resultType="User">

          select * from user

     </select>

     */

     public List<User>  all();    //这是接口中的方法

    

 


 

(二)Mybatis怎么做的?

    @Test
     public void testMapper(){

          SqlSession session = MyBatisUtil.openSession();
          try{
                UserMapper mapper = session.getMapper(UserMapper.class);

                System.out.println(mapper.getClass().getName());

          }finally{
                session.close();
          }
     }

    打印结果:

    $Proxy4

       很简单了,mybatis为接口做了一个动态代理。在执行UserMapper接口上面的方法时,参考接口的全路径名,即可找到对应的UserMapper.xml,在执行接口上面的每一个方法的时候,实际上                 就是在执行namespace+id,mybatis在根据定义的方法的元素,选择调用合适的session的方法来执行,并传入参数就可以。

     使用Mapper接口的方式,在集成Spring+MyBatis也非常方便。因为我们可以直接把Mapper接口看作domain的dao接口了。


 

(三)接口开发的三个特点

  1、     Mapper接口方法名和mapper.xml中定义sql的id值相同

  2、     Mapper接口方法接收的参数类型和mapper.xml中定义的sql 的parameterType的类型相同

  3、     Mapper接口方法的返回值类型和mapper.xml中定义的sql的resultType的类型相同

 


 

(四)自动匹配规范驼峰规则

  数据库中我们习惯使用全大写,多个单词用下划线隔开,而po对象,习惯使用java驼峰规则。那一个一个手工写resultMap字段,浪费开发时间。Mybatis可以配置mapUnderscoreToCamelCase,实现自动映射。这个值默认为true。

   1  sqlMapConfig.xml中配置settings 

<?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>

     <settings>

          <setting name="mapUnderscoreToCamelCase" value="true" />

     </settings>

</configuration>
  1.  在XXXmapper文件中  resultMap配置autoMapping="true"

<resultMap type="cn.tedu.jk.domain.Contract" id="contractRM" autoMapping="true">

          <id property="id" column="CONTRACT_ID"/>

 </resultMap>

 

注意:主键需要单独写,其它字段就可以直接利用驼峰规则自动映射。

 


 

(五)SQL模糊查询

   1  参数中直接加入%%(不好)

      如果要发起一条SQL,where name like #{name},name手动传入%大%这里就容易发生SQL注入问题

   2  Sql中用CONCAT函数 (推荐) 三种数据库的字符串拼接

      Sql Server 中没有Concat函数   拼接  直接用  +  号

         Oracle 和 MySQL 可以用Concat进行拼接

    

  

<!-- where 2-->
     <select id="findone2" resultType="User" parameterType="map">
          select <include refid="cols"></include> 
      from user
<where> id=#{id} and addr=#{addr} and name like concat(concat('%',#{name}),'%') </where>    </select>

 


 

(六)【重点】关联关系

  1 准备数据

1.3.1.1  用户表user_info
create table user_info(

id int primary key auto_increment,

user_name varchar(100),

user_addr varchar(200),

user_age int);

set names gbk;

insert into user_info values(null,’韩梅梅’,’上海’,20);

insert into user_info values(null,’王海涛’,’北京’,30);

insert into user_info values(null,’张慎政’,’河南’,10);

1.3.1.2  用户扩展表user_extra
create table user_extra(

id int primary key auto_increment,

user_id int,

work varchar(100),

salary double);

insert into user_extra values(null,’1’,’程序员’,100000);

insert into user_extra values(null, ’2’,’教师’,1000);

insert into user_extra values(null, ’3’,’CTO’,100000);

1.3.1.3  订单表orders
create table orders(

id int primary key auto_increment,

user_id int,

order_no int,

order_desc varchar(100),

price double);

insert into orders values(null,1,100,’好评’,1000);

insert into orders values(null,2,200,’优秀’,100);

insert into orders values(null,1,300,’优秀’,100);

insert into orders values(null,1,400,’优秀’,100);

  封装对象

public class UserInfo {
      //id映射
      private int id;
      //user_name映射
      private String userName;
      //user_addr映射
      private String userAddr;
      //user_age映射
      private int userAge;

    自己生成一下get,set方法,和toString 方法 (Ecilipse快捷键 SHIFT+ALT+S)
}

 

public class UserExtra {
      //id映射
      private int id;
      //work映射
      private String work;
      //salary映射
      private double salary;
      //user_id映射(对应user表的id)
      private int userId;
    自己生成一下get,set方法,和toString 方法 (Ecilipse快捷键 SHIFT+ALT+S)
}

 

public class Orders {
      //id映射
      private int id;
      //user_id映射
      private int userId;
      //order_no映射
      private int orderNo;
      //order_desc映射
      private String orderDesc;
      //price映射
      private double price;
     自己生成一下get,set方法,和toString 方法 (Ecilipse快捷键 SHIFT+ALT+S)
}

     3 根据用户查询一对一关系的用户扩展信息,使用association  +  javaType

     3.1改造UserInfo对象 (将UserExtra对象引入)

public class UserInfo {
      private int id;
      private String userName;
      private String userAddr;
      private int userAge;    

      //一对一  

    private UserExtra userExtra;
    自己生成一下get,set方法,和toString 方法 (Ecilipse快捷键 SHIFT+ALT+S)
}

        3.2编写UserInfoMapper.xml(引入核心配置文件中去!!association  +  javaType

<?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="cn.tedu.dao.UserInfoDao">
<!-- 一对一的UserExtra信息
           type=""  把数据封装给哪个实体对象(全路径)
           id="userExtraRM" 唯一标志
      -->
      <resultMap type="cn.tedu.pojo.UserInfo"
                      id="userExtraRM">
           <!-- association用来描述一对一关系
                 property="userExtra"  在UserInfo中的属性
                 javaType=""  关联对象的类的全路径...
           -->
      <association property="userExtra" javaType="cn.tedu.pojo.UserExtra">
                 <!-- 描述UserExtra信息... -->
                 <id column="id" property="id" />
                 <result column="work" property="work" />
                 <result column="salary" property="salary" />
                 <result column="user_id" property="userId" />
           </association>
      </resultMap>
    <!-- 根据用户id查询用户详情 -->
    <!-- 一对一的关联查询 resultMap="" 引用上面大的结果集,id值 -->
      <select id="getExtraByUserId"
                 resultMap="userExtraRM">
           select * from
           user_info t1,
           user_extra t2
           where
           t1.id=t2.user_id
           and t1.id=#{id}
      </select>
</mapper>

   3.3 创建UserInfoDAO接口

public interface UserInfoDao {

      //根据用户id查询用户的信息,一对一
      public UserInfo getExtraByUserId(int userId);
 

}

    3.4测试代码 

public class ORMTest {
//   1,读取配置文件,创建ssf对象
      SqlSessionFactory ssf;
      @Before
      public void init(){
           try {
                 InputStream inputStream =
                            Resources.getResourceAsStream(
                                       "sqlMapConfig.xml");
                 ssf = new SqlSessionFactoryBuilder()
                            .build(inputStream);
           } catch (IOException e) {
                 e.printStackTrace();
           }
      }
      //测试对象的一对一关系
      @Test
      public void One2One(){
           //创建sqlsession,执行SQL
           SqlSession session = ssf.openSession();
           //接口开发
           UserInfoDao dao = session.getMapper(UserInfoDao.class);
           //调用接口方法
           UserInfo info = dao.getExtraByUserId(1);
           System.out.println(info);
           session.close();
      }
}

   4 一对多  查询用户的所有订单,使用collection  +  ofType

  4.1改造UserInfo对象 (将UserExtra对象引入)

public class UserInfo {
      private int id;
      private String userName;
      private String userAddr;
      private int userAge;
      private UserExtra userExtra;    

    //一对多

      private List<Orders> orders;
   自己生成一下get,set方法,和toString 方法 (Ecilipse快捷键 SHIFT+ALT+S)
}

  4.2 改造UserInfoMapper.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="cn.tedu.dao.UserInfoDao">
 <!-- 一对多的关联关系 type="" 结果集封装到哪个对象身上 extends="userInfoRM" 和其他resultMap的关联关系 -->
      <resultMap type="cn.tedu.pojo.UserInfo"
                 id="ordersRM"
           extends="userInfoRM">
           <!-- 多的一方Orders的对象信息 property="" UserInfo对象中的属性名 ofType="" 关联对象Orders的全路径 -->
           <collection property="orders" ofType="cn.tedu.pojo.Orders">
                 <!-- 描述Orders的信息 -->
                 <id column="id" property="id" />
                 <!-- 普通字段 -->
                 <result column="user_id" property="userId" />
                 <result column="order_no" property="orderNo" />
                 <result column="order_desc" property="orderDesc" />
                 <result column="price" property="price" />
           </collection>
      </resultMap>
</mapper>

 

增加关联查询的SQL
注意:结果集中,不要出现同名的字段,否则封装不成功!!如果出现重复字段,以结果集为准,重新映射column关系。
      <!-- 根据用户id查询订单信息
           resultMap="ordersRM"引用其他resultMap,id值
      -->
      <select id="getOrdersByUserId"
                 resultMap="ordersRM">
           select * from
           user_info t1,
           orders t2
           where t1.id=t2.user_id
           and t1.id=#{id}
      </select>

   4.3改造UserInfoDao接口

public interface UserInfoDao {
      //根据用户id查询用户的信息,一对一
      public UserInfo getExtraByUserId(int userId);
      //据用户id查询订单信息
      public List<UserInfo>
                 getOrdersByUserId(int userId);
}

 4.4改造测试类

      @Test
      public void One2Many(){
           //创建sqlsession,执行SQL
           SqlSession session = ssf.openSession();
           //接口开发
           UserInfoDao dao =
                      session.getMapper(UserInfoDao.class);
           //调用接口方法,根据用户id查询订单
           List<UserInfo> list =
                      dao.getOrdersByUserId(1);
           for (UserInfo userInfo : list) {
                 System.out.println(userInfo);
           }
           session.close();
      }  

 

 


 

 

    相信一万小时天才理论

      最穷不过要饭,不死终会出头! 

 

posted @ 2018-10-16 19:51  朝才  阅读(8608)  评论(2编辑  收藏  举报