iintothewind
V2EX  ›  Java

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

  •  1
     
  •   iintothewind · Aug 16, 2024 · 10559 views
    This topic created in 809 days ago, the information mentioned may be changed or developed.
    很多集合操作本来可以很方便的 paralStream 然后调用数据库处理,
    或者从 servlet 主线程拿到数据提交异步操作处理。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    今天这些框架不支持
    明天有没有 session plus 取决于你的执行力
    iintothewind
    iintothewind
    OP
    Aug 17, 2024
    58
    @Chinsung 这个跟 spring 没关系的。
    iintothewind
    iintothewind
    OP
    Aug 17, 2024
    59
    @cs419
    @ZGame 其实在多线程上线文里,session 跟 connection 是一回事,linq 及其类似组件都是依赖 connection 构建的, 本身后续的都是一系列流式的操作, 而这些操作既没有暴露 connection 也没有改变 connection 的状态, 所以才是线程安全的。 所以才说, 数据访问层的设计其实不需要有 session ,也可以做的很好用。
    chaoschick
    chaoschick
    Aug 17, 2024
    60
    太年轻了
    iintothewind
    iintothewind
    OP
    Aug 17, 2024
    61
    @chaoschick 哈哈哈,听到有人这么说,我真的很开心啊。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   4405 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 85ms · UTC 03:55 · PVG 11:55 · LAX 19:55 · JFK 22:55
    ♥ Do have faith in what you're doing.