V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iintothewind
V2EX  ›  Java

hibernate 和 mybatis 的 session 都不是线程安全的,为什么还要用?

  •  1
     
  •   iintothewind · 78 天前 · 4326 次点击
    这是一个创建于 78 天前的主题,其中的信息可能已经有所发展或是发生改变。
    很多集合操作本来可以很方便的 paralStream 然后调用数据库处理,
    或者从 servlet 主线程拿到数据提交异步操作处理。

    但由于 hibernate 和 mybatis 的 session 都不是线程安全的,
    导致在多线程环境下,
    通过 hibernate 和 mybatis 的数据库改动可能会出现问题,

    如果从多线程操作数据库的角度考虑,
    我是真的不喜欢这俩老掉牙的难用的框架,
    真的不喜欢。

    大家有什么看法?
    61 条回复    2024-08-17 07:25:33 +08:00
    blankmiss
        1
    blankmiss  
       78 天前
    你确定不是事务问题?
    iintothewind
        2
    iintothewind  
    OP
       78 天前
    @blankmiss 不是,
    因为不管是用不用事务,
    只要在子线程改变了数据库,
    session 都无法同步啊。
    Bingchunmoli
        3
    Bingchunmoli  
       78 天前 via Android
    线程安全难道不是=事务串行化?
    chendy
        4
    chendy  
       78 天前   ❤️ 5
    不是,哥们,啥需求啥场景啊,为了用个 parallel 连持久层框架都看不上了?
    而且你这问题不是持久层框架的问题,四舍五入是数据库的问题
    因为 session 简单理解其实就是一个连接,既然只有一个连接,连接这玩意本身也不是线程安全的
    想象一下,俩线程拿着同一个连接给数据库怼 SQL ,想想都头大。就算有好心的厂家给加了个 syncronized ,一个线程操作还没完,另一个线程直接一个 commit ,想想头更大了

    所以说…还是优化一下代码设计吧,持久层框架不背这个锅
    leegradyllljjjj
        5
    leegradyllljjjj  
       78 天前 via iPhone
    不要问问就是 lock
    miaotaizi
        6
    miaotaizi  
       78 天前
    我能不能理解为 你没用好多线程?
    m2276699
        7
    m2276699  
       78 天前
    对象面错了?
    vituralfuture
        8
    vituralfuture  
       78 天前 via Android
    我怀疑你说的就是 ACID
    Goooooos
        9
    Goooooos  
       78 天前
    说个你认知能力内是数据库连接线程安全的 ORM 框架,不限语言,好让我开开眼界、学习学习新知识
    liumao
        10
    liumao  
       78 天前
    可以看看你的代码吗
    iintothewind
        11
    iintothewind  
    OP
       78 天前
    @Bingchunmoli
    @chendy
    @miaotaizi

    我不明白, 明明 session 不支持多线程导致 parallelStream 之后的操作都不支持,
    这是因为 Hibernate ,MyBatis 这么老的框架在架构之初,parallelStream 根本就不存在导致的,因为 Hibernate ,MyBatis 太老了,该换掉了,我说的是这个设计的缺陷, 怎么就老扯别的????

    我当然知道因为 session 不支持多线程想办法绕过啊,
    不在多线程环境用, 加锁。。。。。等等,

    我说的是框架上设计的不足
    如果这俩框架本身就支持多线程下操作数据库,不是更好吗?
    iintothewind
        12
    iintothewind  
    OP
       78 天前
    @Goooooos try google "jdbi threadsafe", you are welcome, dude.
    Goooooos
        13
    Goooooos  
       78 天前
    @iintothewind #12 呃,你理解的是这样
    cheng6563
        14
    cheng6563  
       78 天前
    非现场安全的库多了去了,你就都别用呗。
    iyiluo
        15
    iyiluo  
       78 天前
    这两个框架不用,还能用啥,手搓 jdbc 吗
    chendy
        16
    chendy  
       78 天前
    @iintothewind
    > Hibernate ,MyBatis 这么老的框架在架构之初,parallelStream 根本就不存在导致的

    parallelStream 确实不存在,但是多线程机制早就存在了,以前怎么处理多线程,parallelStream 里怎么处理就行了

    > 如果这俩框架本身就支持多线程下操作数据库,不是更好吗?

    问题在于,什么叫支持多线程操作数据库?如果想保证基本的操作,加个锁就行不用框架动;如果操作复杂,要处理比如谁前谁后,谁和谁抢锁,谁和谁联动,这么多细节问题也不是框架能决定的,是写代码的人决定的

    > 因为 Hibernate ,MyBatis 太老了,该换掉了

    换成啥也处理不了你这个需求,多线程下的复杂逻辑本来就应该是自己写的
    hi9527
        17
    hi9527  
       78 天前
    @Goooooos #9 django 框架数据库连接线程安全吗
    https://chatgpt.com/share/465f22a8-481c-4aeb-a97a-0972b8c8f48f

    看到你们的讨论来了点兴趣,问了下机器人,不知道是不是符合你们聊的主题
    geligaoli
        18
    geligaoli  
       78 天前   ❤️ 2
    为何要 parallelStream 并行操作数据库?
    数据库的建立连接是很耗资源的,要不就没有连接池的概念了。 正常的流程,不应该是 单线程读取数据 => 放到集合中 => parallelStream 处理集合 => 单线程写回数据库 ,这样的么?
    Vegetable
        19
    Vegetable  
       78 天前   ❤️ 1
    给我干懵了,这就是 JAVA 程序员的含金量吗?
    什么框架的 Session 是线程安全的啊?哪有这种东西?想实现你的安全必须给每个线程自动初始化隔离的 Session ,你听听这是人话吗,什么框架敢这么干?
    如果你想并行处理,请自己管理互相隔离的数据库连接,而不是期待着 spring 帮你搞定,不要硬黑。
    seedscoder
        20
    seedscoder  
       78 天前
    `Spring` 和 `Mybatis` 整合之后,底层使用 `SqlSessionTemplate` 似乎是能做到线程安全?
    Goooooos
        21
    Goooooos  
       78 天前   ❤️ 1
    @hi9527 每个线程要操作数据库前都需要从连接池里取出一个连接,这个连接并非线程安全,不能多个线程同时使用同一个数据库连接。
    可以认为,mybatis 的一个 session 就代表一个数据库连接。
    hefish
        22
    hefish  
       78 天前
    我觉得 op 说的很对,要是有一个啥都支持,啥都支持的非常非常非常好的框架,那就完美了。。。
    cleanery
        23
    cleanery  
       78 天前
    “session 都不是线程安全的”
    要不听听你在说什么,session 不能共享,这不是很正常的?
    session 和一个事物是绑定的,一般来说,每个线程都是通过 SqlSessionFactory 创建自己的 session 。
    我第一次见到有人把 session 用到多线程环境的
    cleanery
        24
    cleanery  
       78 天前
    @cleanery 事物->事务
    GoRoad
        25
    GoRoad  
       78 天前
    op 现在全面切成 jdbi 了吗?对比 hibernate 和 mybatis 有什么感觉
    iintothewind
        26
    iintothewind  
    OP
       78 天前
    @Vegetable #19 不讨论技术问题, 就人身攻击, 而且直接针对所有 java 开发者? 这就是你的含金量?
    干的漂亮! 兄弟.
    可是我不止用 java, 我用好多其他语言, 你就只用一种开发语言吗? 哥们?
    justNoBody
        27
    justNoBody  
       78 天前
    我想想看看 OP 的代码,脱敏发一下可以么
    iintothewind
        28
    iintothewind  
    OP
       78 天前
    @GoRoad #25 偶尔用, 因为历史原因, 不得不跟 jpa 打交道, 所以只能边吐槽边用啊.
    我是不偏向任何技术,
    觉得好的就说好, 我很喜欢.net 的 linq 可惜 java 没有.
    iseki
        29
    iseki  
       78 天前 via Android   ❤️ 1
    因为在设计上就没打算让你多线程使用 Session 对象,因为单个会话的数据库操作是不能并发的,支持多线程操作单个会话毫无意义。
    GoRoad
        30
    GoRoad  
       78 天前
    @iintothewind #28 那能看一下你在使用 jpa 的时候是怎么处理线程不安全的吗,这方面确实是没注意过
    iintothewind
        31
    iintothewind  
    OP
       78 天前
    @GoRoad #30 我就尽量不用 jpa 在多线程环境下做改变数据库的操作, 只用 select 没问题的, 改动放到主线程就好了啊.
    Ayanokouji
        32
    Ayanokouji  
       78 天前   ❤️ 1
    map 也不是线程安全,是不是也没必要存在了
    iintothewind
        33
    iintothewind  
    OP
       78 天前
    @Ayanokouji #32 "map 也不是线程安全", 你说错了吧? 你想说的是 HashMap 不是线程安全的吧? Map 有很多其它实现啊, java11 之后 Map 支持 Map.ofEntries()创建不可变 Map, 大部分场景你只需要用这个 api 就可以了,而这个 api 创建的 map 是线程安全的, welcome, 兄弟.
    Ayanokouji
        34
    Ayanokouji  
       78 天前
    @iintothewind 有了 Map.ofEntries(),那还要 new hashmap 干啥。你咋不全用 java.util.concurrent 包下的呢
    Ayanokouji
        35
    Ayanokouji  
       78 天前
    Vector 是线程安全的,你把 arrayList 都替换掉啊
    iintothewind
        36
    iintothewind  
    OP
       78 天前
    @Ayanokouji #35 抬杠好玩吗? 哈哈哈
    Ayanokouji
        37
    Ayanokouji  
       78 天前
    @iintothewind 你自己菜,连个问题都不会问,讲不过就只会说抬杠。再说了 Java 有真正的 Immutable 吗,反射照样改,照样能做到线程不安全,你啥也别用啊。java 自己还有 unsafe api ,继续解释啊。
    RandomJoke
        38
    RandomJoke  
       78 天前   ❤️ 4
    1. 本身用公共池的 parallelStream 就不适合处理 io 密集的任务,把 io 任务和计算任务放一起会有很多问题
    2. SessionFactory 是线程安全的
    3. session 用来处理事务的,和多线程本身就有冲突啊- -
    iintothewind
        39
    iintothewind  
    OP
       78 天前
    @Ayanokouji 你赢了,😄
    iintothewind
        40
    iintothewind  
    OP
       78 天前
    @geligaoli #18 没错, 我用 jpa 时就是这样的用法, 但还是想吐槽, 唉.
    NeroKamin
        41
    NeroKamin  
       78 天前
    你想要的是一个能够自动维护管理各线程 session 的东西,而不应该是一个线程安全的 session ,否则就是你对 session 的理解有误
    iintothewind
        42
    iintothewind  
    OP
       78 天前
    @NeroKamin #41 其实框架设计的时候就不设计 session, 直接处理就好了, jpa 标准并不重要.
    NeroKamin
        43
    NeroKamin  
       78 天前
    @iintothewind #42 怎么可能不设计 session ,session 是和数据库交互所必需的。而且有这个东西也不意味着你必须得用这个啊,你可以用 SessionFactory 来管理 session 而避免直接使用 Session ,或者不满足你的需求你可以自己再进行封装。
    iintothewind
        44
    iintothewind  
    OP
       78 天前
    @NeroKamin #43 .net 的 linq 如何? 有 session 吗?
    iPisces77
        45
    iPisces77  
       78 天前
    parallelStream()我就用来导入数据,没有任何问题呀
    interim
        46
    interim  
       78 天前
    @Vegetable 这就是地图炮的含金量?
    lucasdev
        47
    lucasdev  
       78 天前   ❤️ 1
    我说说个人理解哈:
    1. 在 parallelStream 之前,Java 又不是没有多线程,Session 不是线程安全与它老不老掉牙没什么关系吧
    2. Session 是用来管理数据库连接和事务的,肯定不能多线程共享,但在每个线程中 openSession 是不是可以满足楼主需求?
    3. LINQ providers ,例如 LINQ To SQL 的 DataContext 、Entity Framework 的 DbContext ,和 Session 是类似的概念,它们也不是线程安全的
    NeroKamin
        48
    NeroKamin  
       78 天前
    @iintothewind #44 linq 只是处理数据的抽象层而已,为什么拿来和 hibernate 和 mybatis 对比?
    ZGame
        49
    ZGame  
       78 天前
    @iintothewind c#的 Linq 不是指查询数据库,Linq to Sql 通过 DataContext 去和数据库连接 ,他应该也不是线程安全的。。
    wantstark
        50
    wantstark  
       78 天前
    这个问题问的、真无趣
    ByteFlow
        51
    ByteFlow  
       78 天前   ❤️ 1
    使用 `SqlSessionFactoryBuilder` 默认创建的是 `DefaultSqlSessionFactory`。应该是可以使用另一个实现类 [`SqlSessionManager`]( https://github.com/mybatis/mybatis-3/blob/master/src/main/java/org/apache/ibatis/session/SqlSessionManager.java) 这个类代替的,这个类每次都会获取当前线程绑定的 `SqlSession`,应该是可以完成你说的任务的。这个类网上资料比较少,可以试一下。
    summerLast
        52
    summerLast  
       78 天前   ❤️ 1
    您说的有道理,问题是哪些部分是可并行的哪些部分是需要串行的,还有两者如何更好的结合对这个问题会更有帮助,

    针对不可并行的任务并性化操作时,框架如果能直接设置当前是否多线程调用,然后进行锁的操作或抛出异常对开发者心智要求也会降低,门槛也会降低,如果框架没有该功能就需要开发者针对自己的场景进行处理,这一切也没那么难,但如果有会更好一些

    回到问题为什么还要用 没有更好的替代。
    hzgit
        53
    hzgit  
       78 天前
    我感觉 LZ 可能搞错问题的方向了,推荐了解下连接池,看看是不是能解决你的问题
    summerLast
        54
    summerLast  
       78 天前
    根据目前的硬件架构 多线程操作同一资源,锁是必须存在,锁的开启和关闭是有开销代价的,因此锁不在数据库层就在 应用层,而锁要不要用显然应用层会更好区分这个问题,至于是放在框架还是放在业务代码,这个就仁者见仁智者见智了,redis 就没这个心智负担
    Chinsung
        55
    Chinsung  
       78 天前
    你确定是这俩玩意的问题?
    作用域:
    单例( Singleton ):在整个应用程序中只创建一个 bean 实例,默认为单例。
    原型( Prototype ):每次请求时都会创建一个新的 bean 实例。
    会话( Session ):在 Web 应用程序中,每个会话都会创建一个 bean 实例。
    请求( Request ):在 Web 应用程序中,每个请求都会创建一个 bean 实例。

    你可以试试每次都创新一个新的 hibernate 或者 mybatis 实例来使用,看看到底是哪层的问题

    按照你的描述来说,如果是 hibernate 或者 mybatis 不支持多线程使用,不应该是 sql 执行结果不对,而是经常生成的 sql 错误,不是吗?
    Plutooo
        56
    Plutooo  
       78 天前
    难道不是多线程操作数据库本身就破坏了隔离性?
    cs419
        57
    cs419  
       78 天前   ❤️ 1
    众口难调,流行的框架都是面向大众需求的
    这种少见的用法 也不是不支持
    看了下 mybatis 框架 给你留口子了

    接口 SqlSessionFactory 与默认实现 DefaultSqlSessionFactory
    SqlSession 与 DefaultSqlSession
    自己包一下 就成了
    你再发布到仓库 大伙都能用上

    就好比 自动填充创建时间、更新时间、多租户等等
    mybatis 官方没这些功能
    mybatis plus 可以

    今天这些框架不支持
    明天有没有 session plus 取决于你的执行力
    iintothewind
        58
    iintothewind  
    OP
       78 天前
    @Chinsung 这个跟 spring 没关系的。
    iintothewind
        59
    iintothewind  
    OP
       78 天前
    @cs419
    @ZGame 其实在多线程上线文里,session 跟 connection 是一回事,linq 及其类似组件都是依赖 connection 构建的, 本身后续的都是一系列流式的操作, 而这些操作既没有暴露 connection 也没有改变 connection 的状态, 所以才是线程安全的。 所以才说, 数据访问层的设计其实不需要有 session ,也可以做的很好用。
    chaoschick
        60
    chaoschick  
       77 天前
    太年轻了
    iintothewind
        61
    iintothewind  
    OP
       77 天前
    @chaoschick 哈哈哈,听到有人这么说,我真的很开心啊。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   986 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 20:21 · PVG 04:21 · LAX 13:21 · JFK 16:21
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.