使用javabean getXX与setXX保存无法自动生成主键问题

波总,跟您请教个问题代码如下^_^//:

1、服务层代码:

 /**
  * 保存
  * @param log
  * @return
  */
 public boolean save(SLog log) {
   if (null == log) {
      log = new SLog();
   }
   
   if (dao.put(log).save()) {
if (!sl.isEmpty(log.getId())) {
   CacheKit.remove(SLog.CacheName.NAME, log.getId());
} else {
   CacheKit.remove(SLog.CacheName.NAME, SLog.CacheKey.KEY);
}

      return true;
   }
   
   return false;
 }

2、控制层代码:

if (1 == fn) {
    Resource resource = matchRecordLogUrl(request);
    if (null != resource) {
        SLog sLog = new SLog();
        int uid = controller.getCookieToInt(Const.Co._USER, 1);
        String username = "游客";
        if (!sl.isEmpty(uid)) {
            username = UserService.me.findById(uid).getName();
        }
        sLog.setUsername(username);
        sLog.setName(resource.getName());
        sLog.setUrl(resource.getUrl());
        sLog.setType(1);
        sLog.setIp(request.getRemoteAddr());
        sLog.setInfo("成功!");
        sLog.setStatus(fn);
        sLog.setCreateAt(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        LogService.me.save(sLog);
    }
}

备注:

        (1)、数据库是mysql库,数据库主键已经设置自动增长,数据保存时主键不自增问题。

        (2)、参数传递是javabean模式,也就是说在做参数传递时,传的是javabean 的 getxx或setxx的这种形式。

评论区

JFinal

2016-10-29 17:34

看到 dao.put(log).save() 这样的代码,就知道大错特错了,jfinal 手册有红色字体明确说明过

dao 是 static 声明的全局共享的东西,不同线程在使用它的时候,数据是共享的,那么你第一次 dao.put 进去东西,第二再使用的时候与第一次会混乱,如果是多线程并发使用,数据是乱窜

所以 jfinal 最佳实践已经明确明说了,要将 Model 中的 dao 彻底删掉,避免这样的误用

删掉以后,查询的时候可以 new Xxx().find(sql) 这样就永远没有线程安全问题了

lyh061619

2016-10-29 22:34

@JFinal
1、dao不是静态的哦,service层定义:
/**
* 日志服务层
* Created by slsoft on 2016/10/6.
*/
public class LogService {
public static final LogService me = new LogService();
final SLog dao = new SLog();

2、现在修改成:
/**
* 日志服务层
* Created by slsoft on 2016/10/6.
*/
public class LogService {
public static final LogService me = new LogService();
SLog dao = new SLog();
把final去掉问题解决了。

JFinal

2016-10-29 22:39

@lyh061619 去掉 final 没有意义,虽然这里不是 static 的,但是如果多线程使用的是同一个 LogService 对象,那么与使用 static 在本质上是一样的错误,总之这里的 dao 是共享变量,不能用于 set、put、save、update 等一切写数据的操作,只能使用 find 系列的方法

JFinal

2016-10-29 22:41

除非你将 static final LogService me 这一行代码去掉,那么 dao 则不是共享的,此外,还要保障在外部没有类似 static LogService 的定义, static 是有传递性的,这是 java 基础,建议多了解一下

lyh061619

2016-10-29 23:21

@JFinal 我这个,参照波您回答这个做的:http://www.jfinal.com/feedback/296,不过我在保存是用了.put,哈哈。

JFinal

2016-10-30 00:18

@lyh061619 在业务层创建 dao 是可以的,但仍然不要去调用它的 dao.put/save/update/set 之类的方法,这个对象是共享的,不是线程安全的, java 这门语言是多线程语言,必须要考虑对象在多线程共享情况下的线程安全问题,这是极其重要的java基础知识,必须要对java 线程极其熟悉才能写出健壮的程序

lyh061619

2016-10-30 09:24

@JFinal 嗯,那我在业务层new Xxx().put()/save/update的话,因为每调用一次对像都被new一次,在堆中分配一块新的内存空间,这样的话就不存在对象共享了。

JFinal

2016-10-30 11:12

@lyh061619 孺子可教也,是这么回事 ^_^

lyh061619

2016-10-30 11:17

@JFinal 波总见笑啦^_^---

lyh061619

2016-10-30 15:51

@JFinal 波总,上面提到new Xxx().put()/save/update后,那我业务层的public static final LogService me = new LogService 在这段,在多线程下可以在控制层正常使用的吧?,我个人认为在每个操作数据折地方已经修改为new Xxx().put()/save/update/find后,其他地方使用LogService.me.xxx()方法的话就不有线程不安全问题出现了,不知道是否理解正确,请教下波总^_^_^。

JFinal

2016-10-30 17:55

@lyh061619 是否有线程安全问题,不在于有没有使用 static,也不在于有没有共享变量,而在于对共享变量的使用方式

例如,你在 LogService 类中除了定义了这个 me 对象以外,完全没有定义任何其它任何属性,何来线程安全这一说? 因为根本没有共享的对象可言,而 me 这个对象虽然是共享的,但是它没有属性,只有方法,方法中 new 出来的变量是在方法用完后被释放的,没有线程安全问题

还有一种变量共享是绝对安全的,例如你有一个对象是只读的,那么任何线程拿到的值是一样的,也就不存在线程安全问程

总之只需要去了解,多个线程在访问同一块数据区域的时候,会不会造成数据混乱即可,不要被任何形式所拘泥,此外建议你多看看 java 线程安全方面的资料,极度重要

JFinal

2016-10-30 17:58

在有 static Xxx dao 对象的时候,如果你只使用 find 系列的方法也是线程安全的,因为 find 系列的方法中所使用的对象不涉及共享变量,全都是方法内部 new 出来的对象,所以是安全的

而 dao 中的 save、put、update 等方法,操作的数据是该 dao 对象内部所持有的 Map attrs 这个属性,这个属性是对所有线程可见的,在操作它的时候就不是线程安全的

lyh061619

2016-10-30 18:49

@JFinal 谢谢波总的耐心指点。\\^_^//

大海龟

2016-11-01 18:50

受教了

热门反馈

扫码入社