hibernate 和 mybatis 的 session 都不是线程安全的,为什么还要用? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iintothewind
V2EX    Java

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    今天这些框架不支持
    明天有没有 session plus 取决于你的执行力
    iintothewind
        58
    iintothewind  
    OP
       2024-08-17 00:30:11 +08:00
    @Chinsung 这个跟 spring 没关系的。
    iintothewind
        59
    iintothewind  
    OP
       2024-08-17 00:34:59 +08:00
    @cs419
    @ZGame 其实在多线程上线文里,session 跟 connection 是一回事,linq 及其类似组件都是依赖 connection 构建的, 本身后续的都是一系列流式的操作, 而这些操作既没有暴露 connection 也没有改变 connection 的状态, 所以才是线程安全的。 所以才说, 数据访问层的设计其实不需要有 session ,也可以做的很好用。
    chaoschick
        60
    chaoschick  
       2024-08-17 07:21:57 +08:00
    太年轻了
    iintothewind
        61
    iintothewind  
    OP
       2024-08-17 07:25:33 +08:00
    @chaoschick 哈哈哈,听到有人这么说,我真的很开心啊。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1482 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 31ms UTC 16:35 PVG 00:35 LAX 08:35 JFK 11:35
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86