zoukankan      html  css  js  c++  java
  • Java MyBatis 插入数据库返回主键

    问题?

    如何在Java MyBatis 插入数据库返回主键?

    最近在搞一个电商系统中由于业务需求,需要在插入一条产品信息后返回产品Id,刚开始遇到一些坑,这里做下笔记,以防今后忘记。

    类似下面这段代码一样获取插入后的主键

    复制代码
    User user = new User();  
    user.setUserName("chenzhou");  
    user.setPassword("xxxx");  
    user.setComment("测试插入数据返回主键功能");  
    

    System.out.println("插入前主键为:"+user.getUserId());
    userDao.insertAndGetId(user);
    //插入操作
    System.out.println("插入后主键为:"+user.getUserId());

    复制代码

    解决方案:

    由于鄙人当时的学习水平有限,未能很好处理这个问题,如今再来看这个问题,其实很简单。

    当时我的思维局限于插入数据后不想再次调用查询接口,就直接获取这个插入的主键Id. 因此如果想达到这种效果,最优方案是下面解决方案的第二种方式

     但是其实我们完全可以在插入后再调用下其他查询接口就可以了。

    复制代码
    User user = new User();  
    user.setUserName("chenzhou");  
    user.setPassword("xxxx");  
    user.setComment("测试插入数据返回主键功能");  
    

    System.out.println("插入前主键为:"+user.getUserId());
    userDao.insertAndGetId(user);//插入操作

    User myUser=userDao.findUserByName(user.getName());
    System.out.println("插入后主键为:"+myUser.getUserId());

    复制代码

    不想再次调用查询接口的解决方案

    经过查询网上资料,发现大致有两种方式。

    第一种方式:

    在实体类的映射文件 "*Mapper.xml" 这样写:

    <insert id="insertAndGetId" useGeneratedKeys="true" keyProperty="userId" parameterType="com.chenzhou.mybatis.User">
        insert into user(userName,password,comment)
        values(#{userName},#{password},#{comment})
    </insert>

    Tips:

    useGeneratedKeys="true" 表示给主键设置自增长
    keyProperty="userId"  表示将自增长后的Id赋值给实体类中的userId字段。
    parameterType="com.chenzhou.mybatis.User" 这个属性指向传递的参数实体类

    这里提醒下,<insert></insert> 中没有resultType属性,不要乱加。

    实体类中uerId 要有getter() and setter(); 方法

    由于我在MySQL数据库中建表时候已经设置了字段自增长,故最终我选择了第二种方式。

    第二种方式

    同样在实体类的映射文件 "*Mapper.xml" 但是要这样写:

    复制代码
        <!-- 插入一个商品 -->
        <insert id="insertProduct" parameterType="domain.model.ProductBean" >
           <selectKey resultType="java.lang.Long" order="AFTER" keyProperty="productId">
              SELECT LAST_INSERT_ID()
          </selectKey>
            INSERT INTO t_product(productName,productDesrcible,merchantId)values(#{productName},#{productDesrcible},#{merchantId});
        </insert>
    复制代码

    Tips: 

    <insert></insert> 中没有resultType属性,但是<selectKey></selectKey> 标签是有的。

    order="AFTER" 表示先执行插入语句,之后再执行查询语句。

    可被设置为 BEFORE 或 AFTER。

    如果设置为 BEFORE,那么它会首先选择主键,设置 keyProperty 然后执行插入语句。

    如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 元素-这和如 Oracle 数据库相似,可以在插入语句中嵌入序列调用
    keyProperty="userId"  表示将自增长后的Id赋值给实体类中的userId字段。

    SELECT LAST_INSERT_ID() 表示MySQL语法中查询出刚刚插入的记录自增长Id.

    实体类中uerId 要有getter() and setter(); 方法
    实现需求,上面那些就足够了。

    了解扩展

    这里如果有兴趣的,请继续听我讲一个Mybatis中可能误入的坑。

    为什么Mybatis 中修改添加方法为有返回值后,虽然提示插入数据库成功并且也能读取插入的数据,但是当你打开数据库后就是看不到插入的数据?

    如果在实现上述需求时,想插入后返回主键的话,切记不要这样写。
    复制代码
        @Override
        public Long insertProduct(ProductBean productBean) {
            // TODO Auto-generated method stub
            SqlSession session = MybatisJDBCUtil.currentSession();
    
        ProductIDao productIDao </span>= session.getMapper(ProductIDao.<span style="color: #0000ff; text-decoration: line-through;">class</span>);<span style="color: #008000; text-decoration: line-through;">//</span><span style="color: #008000; text-decoration: line-through;"> 这里*.class
                                                                        </span><span style="color: #008000; text-decoration: line-through;">//</span><span style="color: #008000; text-decoration: line-through;"> 必须对应DAO的接口层</span>
        <span style="color: #0000ff; text-decoration: line-through;">return</span><span style="color: #000000; text-decoration: line-through;"> productIDao.insertProduct(productBean);
        
    }</span></span></pre>
    
    复制代码

    Why?

    因为如果你是像上面这样写,那么执行后返回的也不是你想要的主键Id,而是执行数据库语句后受影响的行数。

    而且,当你执行后你会发现提示插入成功,你用代码也可以读取出插入的数据,但是永远只有一条记录。

    并且,你打开数据库会发现,数据库中没有插入成功任何数据。

    我在这里郁闷了N久,终于发现了关键所在。

    有返回值和没返回值的区别在于:

    有返回值的只是对数据库只读模式访问数据库,对数据库数据不会有任何修改,比如各种方式的查询。

    无返回值的则会以读写模式访问数据库,会对数据库中的数据进行修改,比如删除,增加。

    除此之外,根据个人理解应该mybatis在执行插入语句时会先缓存到构造的一个类似session集合中,然后才去调用底层驱动去操作修改数据库。

    session.commit(); 
    

    MybatisJDBCUtil.closeSession();

    没有返回值得才有上面这两条语句,也就是说执行了这两条语句才会真正执行插入到数据库,对数据库的数据进行修改。

    相反,有返回值的就没有执行这两条语句,所以只是在自己构造的session中执行了添加语句,但是并没有提交到数据库中,故数据库中是没有任何记录的。

    这也就解释了为什么Mybatis 中修改添加方法为有返回值后,虽然提示插入数据库成功,但是当你打开数据库看不到插入的数据。

    Mybatis中插入语句方法种不要有返回值,像这样写是正确的。

    复制代码
        @Override
        public void insertProduct(ProductBean productBean) {
            // TODO Auto-generated method stub
            SqlSession session = MybatisJDBCUtil.currentSession();
    
        ProductIDao productIDao </span>= session.getMapper(ProductIDao.<span style="color: #0000ff;">class</span>);<span style="color: #008000;">//</span><span style="color: #008000;"> 这里*.class
                                                                      </span><span style="color: #008000;">//</span><span style="color: #008000;"> 必须对应DAO的接口层</span>
    

    productIDao.insertProduct(productBean);

    session.commit();

        MybatisJDBCUtil.closeSession();    
    }</span></pre>
    
    复制代码

    参考资料一:https://my.oschina.net/crazybird/blog/379635?p=1
    参考资料二:http://blog.csdn.net/jbgtwang/article/details/7307687
    参考资料三:http://blog.csdn.net/after_you/article/details/53844908
    原文地址:https://www.cnblogs.com/xingyunblog/p/6243179.html
  • 相关阅读:
    django页面分类和继承
    django前端从数据库获取请求参数
    pycharm配置django工程
    django 应用各个py文件代码
    CF. 1428G2. Lucky Numbers(背包DP 二进制优化 贪心)
    HDU. 6566. The Hanged Man(树形背包DP DFS序 重链剖分)
    小米邀请赛 决赛. B. Rikka with Maximum Segment Sum(分治 决策单调性)
    区间树 学习笔记
    CF GYM. 102861M. Machine Gun(主席树)
    2016-2017 ACM-ICPC East Central North America Regional Contest (ECNA 2016) (B, D, G, H)
  • 原文地址:https://www.cnblogs.com/jpfss/p/10955072.html
Copyright © 2011-2022 走看看