mybatis中字段名与实体属性名不一样的情况下插入数据的方法,在xml配置文件里sql语句应该怎么写?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis中字段名与实体属性名不一样的情况下插入数据的方法,在xml配置文件里sql语句应该怎么写?相关的知识,希望对你有一定的参考价值。

查询语句是 MyBatis 中最常用的元素之一,本文涉及mybatis的单表查询操作,关联表有关的查询会后续补充。

巧妇难为无米之炊,要想从数据库中表中取出数据并转化为javaBean,所以,我们要先准备javabean以及与其对应的数据表。

javaBean:

public class President

private int id;
private String name;

@Override
public String toString()
return "President [id=" + id + ", name=" + name + "]";

//get set 方法.....

创建两个对应的数据库表,并插入两条数据:

create table president1(
p_id int not null auto_increment primary key,
p_name varchar(50) not null
);

insert into president1(p_name) values('lily'),('Tom');

create table president2(
id int not null auto_increment primary key,
name varchar(50) not null
);
insert into president2(name) values('lily'),('Tom');
创建两个数据库是为了测试两个不同的查询状况,
数据库字段名与实体类属性名相同

从sql表可以看出president2的字段名与javabean:President的属性名完全相同,这种情况下mybatis的select操作非常简单:

<!-- 从表 president2中查询-->
<select id="getPreByIdPresident2" parameterType="int" resultType="President">
select * from president2 where id=#id
</select>

此时mybatis运用反射机制会将查询返回的结果(id,name)封装成President对象。

如果从表president1中查询,同样采用上面的sql语句

<!-- 从表 president1中查询-->
<select id="getPreByIdPresident1" parameterType="int" resultType="President">
<span style="white-space:pre"> </span>President p1 = session.selectOne(statement+"getPreByIdPresident1", 1);
<span style="white-space:pre"> </span>System.out.println("表president1中查询"+p1);
</select>

此时如果用getPreByIdPresident1进行查询,返回的结果会是null,我们将上面的sql语句在mysql中执行下:

有结果返回,但是返回的字段名为(p_id,p_name)这种结果mybatis在解析时无法与President类对应。多数情况下实体类属性名与数据库表的字段名都会有差异,这种情况如果mybatis不能处理也就太low了。

数据库字段名与实体类属性名不相同
mybatis针对该种情况有两种解决方法,但是归根到底都是同一种实现。

Method1:定义一个ResultMap将数据库字段名与实体类属性名做个映射

我们欲从表president1中查询数据,此时的mapper配置如下:

<resultMap type="President" id="getFromPresident2">
<!-- 主键必须用id标签映射,其他的用非集合用result映射 集合类用collection映射 -->
<!-- column为数据库字段名,property为实体类属性名 -->
<id column="p_id" property="id" />
<result column="p_name" property="name" />
</resultMap>
<select id="getPreByIdPresident1Method1" resultMap="getFromPresident2">
select * from president1 where p_id=#id
</select>

首先定义了一个resultMap,将数据库表的字段名与实体类属性名做了一一对应,其中type为实体类(此处运用的类别名),id为了在select标签中引用映射结果。

在select标签中并没有用resultType属性,而使用了resultMap,即为上面定义的resultMap,mybatis会根据resultMap中的映射关系去构造President

Method1:直接在sql语句中使用别名

<!-- 从表 president1中查询 -->
<select id="getPreByIdPresident1Method2" resultType="President">
select p_id id,p_name name from president1 where p_id=#id
</select>

这种方法会查到实际的数据,这种方法与字段名和属性名相同都是基于相同的原理:MyBatis 会在幕后自动创建一个 ResultMap,基于属性名来映射列到JavaBean 的属性上。即mybatis底层都是通过创建ResultMap来进行关系的映射,与method1原理相同。。追问

谢谢您的解答,但是我想问一下表的字段名与实体类的属性名不同的情况下,插入方法是怎么实现的?

参考技术A

插入方法就这样

Mybatis解决字段名与实体类属性名不相同的冲突

  在平时的开发中,我们表中的字段名和表对应实体类的属性名称不一定都是完全相同的,下面来演示一下这种情况下的如何解决字段名与实体类属性名不相同的冲突。

一、准备演示需要使用的表和数据

CREATE TABLE orders(
    order_id INT PRIMARY KEY AUTO_INCREMENT,
    order_no VARCHAR(20), 
    order_price FLOAT
);
INSERT INTO orders(order_no, order_price) VALUES(aaaa, 23);
INSERT INTO orders(order_no, order_price) VALUES(bbbb, 33);
INSERT INTO orders(order_no, order_price) VALUES(cccc, 22);

二、定义实体类

 1 package me.gacl.domain;
 2 
 3 /**
 4  * @author gacl
 5  * 定义orders表对应的实体类
 6  */
 7 public class Order {
 8     /**
 9      * 
10     CREATE TABLE orders(
11         order_id INT PRIMARY KEY AUTO_INCREMENT,
12         order_no VARCHAR(20), 
13         order_price FLOAT
14     );
15      */
16     
17     //Order实体类中属性名和orders表中的字段名是不一样的
18     private int id;                //id===>order_id
19     private String orderNo;        //orderNo===>order_no
20     private float price;        //price===>order_price
21 
22     public int getId() {
23         return id;
24     }
25 
26     public void setId(int id) {
27         this.id = id;
28     }
29 
30     public String getOrderNo() {
31         return orderNo;
32     }
33 
34     public void setOrderNo(String orderNo) {
35         this.orderNo = orderNo;
36     }
37 
38     public float getPrice() {
39         return price;
40     }
41 
42     public void setPrice(float price) {
43         this.price = price;
44     }
45 
46     @Override
47     public String toString() {
48         return "Order [id=" + id + ", orderNo=" + orderNo + ", price=" + price+ "]";
49     }
50 }

三、编写测试代码

3.1、编写SQL的xml映射文件

  1、创建一个orderMapper.xml文件,orderMapper.xml的内容如下:

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 3 <!-- 为这个mapper指定一个唯一的namespace,namespace的值习惯上设置成包名+sql映射文件名,这样就能够保证namespace的值是唯一的
 4 例如namespace="me.gacl.mapping.orderMapper"就是me.gacl.mapping(包名)+orderMapper(orderMapper.xml文件去除后缀)
 5  -->
 6 <mapper namespace="me.gacl.mapping.orderMapper">
 7     
 8     <!-- 
 9         根据id查询得到一个order对象,使用这个查询是查询不到我们想要的结果的,
10         这主要是因为实体类的属性名和数据库的字段名对应不上的原因,因此无法查询出对应的记录
11      -->
12     <select id="getOrderById" parameterType="int" 
13         resultType="me.gacl.domain.Order">
14         select * from orders where order_id=#{id}
15     </select>
16     
17     <!-- 
18         根据id查询得到一个order对象,使用这个查询是可以正常查询到我们想要的结果的,
19         这是因为我们将查询的字段名都起一个和实体类属性名相同的别名,这样实体类的属性名和查询结果中的字段名就可以一一对应上
20      -->
21     <select id="selectOrder" parameterType="int" 
22         resultType="me.gacl.domain.Order">
23         select order_id id, order_no orderNo,order_price price from orders where order_id=#{id}
24     </select>
25     
26     <!-- 
27     根据id查询得到一个order对象,使用这个查询是可以正常查询到我们想要的结果的,
28     这是因为我们通过<resultMap>映射实体类属性名和表的字段名一一对应关系 -->
29     <select id="selectOrderResultMap" parameterType="int" resultMap="orderResultMap">
30         select * from orders where order_id=#{id}
31     </select>
32     <!--通过<resultMap>映射实体类属性名和表的字段名对应关系 -->
33     <resultMap type="me.gacl.domain.Order" id="orderResultMap">
34         <!-- 用id属性来映射主键字段 -->
35         <id property="id" column="order_id"/>
36         <!-- 用result属性来映射非主键字段 -->
37         <result property="orderNo" column="order_no"/>
38         <result property="price" column="order_price"/>
39     </resultMap>
40     
41 </mapper>

  2、在conf.xml文件中注册orderMapper.xml映射文件

<mappers>        
        <!-- 注册orderMapper.xml文件, 
        orderMapper.xml位于me.gacl.mapping这个包下,所以resource写成me/gacl/mapping/orderMapper.xml-->
        <mapper resource="me/gacl/mapping/orderMapper.xml"/>
</mappers>

3.2、编写单元测试代码

 1 package me.gacl.test;
 2 
 3 import me.gacl.domain.Order;
 4 import me.gacl.util.MyBatisUtil;
 5 import org.apache.ibatis.session.SqlSession;
 6 import org.junit.Test;
 7 
 8 public class Test2 {
 9     
10     @Test
11     public void testGetOrderById(){
12         SqlSession sqlSession = MyBatisUtil.getSqlSession();
13         /**
14          * 映射sql的标识字符串,
15          * me.gacl.mapping.orderMapper是orderMapper.xml文件中mapper标签的namespace属性的值,
16          * getOrderById是select标签的id属性值,通过select标签的id属性值就可以找到要执行的SQL
17          */
18         String statement = "me.gacl.mapping.orderMapper.getOrderById";//映射sql的标识字符串
19         //执行查询操作,将查询结果自动封装成Order对象返回
20         Order order = sqlSession.selectOne(statement,1);//查询orders表中id为1的记录
21         //使用SqlSession执行完SQL之后需要关闭SqlSession
22         sqlSession.close();
23         System.out.println(order);//打印结果:null,也就是没有查询出相应的记录
24     }
25     
26     @Test
27     public void testGetOrderById2(){
28         SqlSession sqlSession = MyBatisUtil.getSqlSession();
29         /**
30          * 映射sql的标识字符串,
31          * me.gacl.mapping.orderMapper是orderMapper.xml文件中mapper标签的namespace属性的值,
32          * selectOrder是select标签的id属性值,通过select标签的id属性值就可以找到要执行的SQL
33          */
34         String statement = "me.gacl.mapping.orderMapper.selectOrder";//映射sql的标识字符串
35         //执行查询操作,将查询结果自动封装成Order对象返回
36         Order order = sqlSession.selectOne(statement,1);//查询orders表中id为1的记录
37         //使用SqlSession执行完SQL之后需要关闭SqlSession
38         sqlSession.close();
39         System.out.println(order);//打印结果:Order [id=1, orderNo=aaaa, price=23.0]
40     }
41     
42     @Test
43     public void testGetOrderById3(){
44         SqlSession sqlSession = MyBatisUtil.getSqlSession();
45         /**
46          * 映射sql的标识字符串,
47          * me.gacl.mapping.orderMapper是orderMapper.xml文件中mapper标签的namespace属性的值,
48          * selectOrderResultMap是select标签的id属性值,通过select标签的id属性值就可以找到要执行的SQL
49          */
50         String statement = "me.gacl.mapping.orderMapper.selectOrderResultMap";//映射sql的标识字符串
51         //执行查询操作,将查询结果自动封装成Order对象返回
52         Order order = sqlSession.selectOne(statement,1);//查询orders表中id为1的记录
53         //使用SqlSession执行完SQL之后需要关闭SqlSession
54         sqlSession.close();
55         System.out.println(order);//打印结果:Order [id=1, orderNo=aaaa, price=23.0]
56     }
57 }

  执行单元测试的结果:

  1、testGetOrderById方法执行查询后返回一个null。

  2、testGetOrderById2方法和testGetOrderById3方法执行查询后可以正常得到想要的结果。

四、总结

  上面的测试代码演示当实体类中的属性名和表中的字段名不一致时,使用MyBatis进行查询操作时无法查询出相应的结果的问题以及针对问题采用的两种办法:

  解决办法一: 通过在查询的sql语句中定义字段名的别名,让字段名的别名和实体类的属性名一致,这样就可以表的字段名和实体类的属性名一一对应上了,这种方式是通过在sql语句中定义别名来解决字段名和属性名的映射关系的。

  解决办法二: 通过<resultMap>来映射字段名和实体类属性名的一一对应关系。这种方式是使用MyBatis提供的解决方式来解决字段名和属性名的映射关系的。

以上是关于mybatis中字段名与实体属性名不一样的情况下插入数据的方法,在xml配置文件里sql语句应该怎么写?的主要内容,如果未能解决你的问题,请参考以下文章

MyBatis学习总结——解决字段名与实体类属性名不相同的冲突(转载)

Mybatis解决字段名与实体类属性名不相同的冲突

MyBatis——解决字段名与实体类属性名不相同的冲突

MyBatis学习总结——解决字段名与实体类属性名不相同的冲突

MyBatis学习总结——解决字段名与实体类属性名不相同的冲突

MyBatis学习总结——解决字段名与实体类属性名不相同的冲突