跳至主要內容

更新

xuejmnet大约 5 分钟

前言

本章节的环境配置请参考环境准备章节

更新对象

Easy Query提供了updatable方法,支持更新单条数据和多条数据,支持批量更新,
如果更新的是对象,则默认按照对象的主键进行更新。

    @Test
    public void testUpdate() {
        User existUser = easyEntityQuery.queryable(User.class).findNotNull(1);
        DateTime updateTime = new DateTime();
        existUser.setUpdateTime(updateTime);
        //更新单条数据
        long rows = easyEntityQuery.updatable(existUser).executeRows();
        Assertions.assertTrue(rows > 0);
        List<User> users = easyEntityQuery.queryable(User.class).where(u -> u.id().in(Arrays.asList(1, 2))).toList();
        for (User user : users) {
            user.setUpdateTime(updateTime);
        }
        //更新多条数据
        rows = easyEntityQuery.updatable(users).executeRows();
        Assertions.assertTrue(rows > 0);
        //批量更新多条数据
        rows = easyEntityQuery.updatable(users).batch().executeRows();
        Assertions.assertEquals(users.size(), rows);
    }

批量更新多条数据时需要配置jdbc连接参数,即rewriteBatchedStatements=true,配置参数后性能将会大幅提升。

注意

调用updatable方法只是获取操作对象,必须再调用executeRows方法再是最终完成更新操作。

更新策略

Easy Query默认采用SQLExecuteStrategyEnum.ALL_COLUMNS策略进行更新,也就是默认更新全列,可以使用setSQLStrategy方法设置执行策略,设置SQLExecuteStrategyEnum.ONLY_NOT_NULL_COLUMNS可以更新非null列。

    @Test
    public void testUpdateAll() {
        User user = easyEntityQuery.queryable(User.class).findNotNull(1);
        DateTime updateTime = new DateTime();
        user.setUpdateTime(updateTime);
        long rows = easyEntityQuery.updatable(user).setSQLStrategy(SQLExecuteStrategyEnum.ONLY_NOT_NULL_COLUMNS).executeRows();
        Assertions.assertTrue(rows > 0);
        Assertions.assertNotNull(user.getId());
    }

更新指定列

调用setColumns方法可以更新指定列。

    @Test
    public void testUpdateCustomColumn() {
        User user = easyEntityQuery.queryable(User.class).findNotNull(1);
        DateTime updateTime = new DateTime();
        user.setUpdateTime(updateTime);
        updateTime.offset(DateField.SECOND, 1);
        long rows = easyEntityQuery.updatable(user)
                .setColumns(o -> o.updateTime())//多个字段使用FETCHER.setColumns(o->o.FETCHER.name().updateTime())
                .whereColumns(o -> o.id())//多个字段使用FETCHER.whereColumns(o->o.FETCHER.id().name())
                .executeRows();
        Assertions.assertTrue(rows > 0);

        updateTime.offset(DateField.SECOND, 1);
        rows = easyEntityQuery.updatable(User.class)
                .setColumns(o -> {
                    o.updateTime().set(updateTime);
                })
                .where(o -> o.id().eq(user.getId()))
                .executeRows();
        Assertions.assertTrue(rows > 0);

        //更新指定列并断言
        updateTime.offset(DateField.SECOND, 1);
        easyEntityQuery.updatable(User.class)
                .setColumns(o -> {
                    o.updateTime().set(updateTime);
                })
                .where(o -> o.id().eq(user.getId()))
                .executeRows(1, "更新失败");
    }

调用set方法后可以继续链式调用对其它列进行set

注意

调用executeRows方法断言受影响行数时,如果不匹配则会抛异常,如果当前操作不在事务内执行那么会自动开启事务!!!会自动开启事务!!!会自动开启事务!!!来实现并发更新控制,因此当前的更新操作将失效

列值类型自动转换

将一个表的列值设为另一个列值时,支持列类型自动转换,比如将name设为id值。

    @Test
    public void testUpdateColumnType() {
        long rows = easyEntityQuery.updatable(User.class)
                .setColumns(o -> {
                    o.name().set(o.id().toStr());
                    //toStr和.setPropertyType(String.class)效果是一样的
                    o.name().set(o.id().setPropertyType(String.class));
                })
                .whereById("1")
                .executeRows();
        Assertions.assertTrue(rows > 0);
    }

列值自更新

Easy Query支持调用increment方法对字段值自增, 默认自增1,可以传入指定的参数值进行自增,另外可以使用decrement方法对字段值自减。

    @Test
    public void testUpdateIncrement() {
        User user = easyEntityQuery.queryable(User.class).findNotNull(1);
        //自增,可传入指定参数自增
        long rows = easyEntityQuery.updatable(User.class)
                .setColumns(o -> {
                    o.version().increment();
                })
                .where(o -> o.id().eq(user.getId()))
                .executeRows();
        Assertions.assertTrue(rows > 0);
    }

差异更新

Easy Query支持差异更新,差异更新可以自动监听被追踪的对象,并且生成差异更新语句,而不是无脑的对对象进行全字段更新,使用时需要开启当前追踪环境并且对查询出来的结果进行追踪后续即可监听到变更列实现差异化update语句

我们可以在调用queryable方法后调用asTracking方法直接追踪查询的对象,在更新对象时只更新其有变化的字段值。

    @Test
    public void testAsTracking() {
        TrackManager trackManager = easyEntityQuery.getRuntimeContext().getTrackManager();
        try {
            trackManager.begin();
            Integer id = 1;
            User existUser = easyEntityQuery.queryable(User.class).asTracking().findNotNull(id);
            existUser.setVersion(existUser.getVersion() + 1);
            easyEntityQuery.updatable(existUser).executeRows();
        } finally {
            trackManager.release();
        }
    }

在本例中,调用asTracking方法后,Easy Query将第一次记录查询出来的对象的状态,
在调用updatable方法更新后,Easy Query将比对本次对象与第一次记录的对象之间的差异,
在执行UPDATE语句时只会更新version字段值。

一般情况下都是追踪查询结果,如果每次查询之后都要调用asTracking方法是很麻烦的,调用setDefaultTrack方法设为true开启默认追踪。

        EasyQueryClient easyQueryClient = EasyQueryBootstrapper.defaultBuilderConfiguration()
                .setDefaultDataSource(dataSource)
                .optionConfigure(op -> {
                    op.setDefaultTrack(true);
                })

开启默认追踪后,Easy Query将为每一次queryable方法调用后默认调用asTracking方法,
对于某些查询方法不希望Easy Query默认调用asTracking方法,那么可以调用asNoTracking方法去除默认调用。

注意

调用trackManager.begin方法后将开启上下文追踪,只有在开启上下文追踪后,追踪对象才会生效,否则无论是否自动调用asTracking方法追踪对象都将无效

除了追踪查询的对象,也可以调用addTracking方法追踪指定对象的差异变化,比如查询结果有多个对象,可以只追踪查询结果的其中一个对象。

    @Test
    public void testAddTracking() {
        TrackManager trackManager = easyEntityQuery.getRuntimeContext().getTrackManager();
        try {
            trackManager.begin();
            Integer id = 1;
            User existUser = easyEntityQuery.queryable(User.class).findNotNull(id);
            easyEntityQuery.addTracking(existUser);
            existUser.setVersion(existUser.getVersion() + 1);
            easyEntityQuery.updatable(existUser).executeRows();
        } finally {
            trackManager.release();
        }
    }

在本例中,调用addTracking方法后,Easy Query将第一次记录指定的对象的状态,
在调用updatable方法更新后,Easy Query将比对本次对象与第一次记录的对象之间的差异,
在执行UPDATE语句时只会更新version字段值。

每次都需要调用trackManager.begin方法开启上下文追踪,以及调用trackManager.release方法释放资源。
在Spring Boot环境下,类似Spring的@Transactional,只需使用Easy Query提供的@EasyQueryTrack即可简化操作。

    @EasyQueryTrack
    public void testAddTracking() {
        trackManager.begin();
        Integer id = 1;
        User existUser = easyEntityQuery.queryable(User.class).findNotNull(id);
        easyEntityQuery.addTracking(existUser);
        existUser.setVersion(existUser.getVersion() + 1);
        easyEntityQuery.updatable(existUser).executeRows();
    }

更新Map

Easy Query也支持更新Map对象,注意,key是列名,不是实体类的属性名。

    @Test
    public void testUpdateMap() {
        Map<String, Object> userMap = new LinkedHashMap<>();
        userMap.put("id", 1);
        userMap.put("update_time", new Date());
        long rows = easyEntityQuery.mapUpdatable(userMap)
                .asTable("user")
                .setSQLStrategy(SQLExecuteStrategyEnum.ONLY_NOT_NULL_COLUMNS)
                .whereColumns("id")
                .executeRows();
        Assertions.assertTrue(rows > 0);
    }

更新自定义sql

Easy Query支持更新时自定义sql。

    @Test
    public void testUpdateCustomSQL() {
        long rows = easyEntityQuery.updatable(User.class)
                .setColumns(o -> {
                    o.version().setSQL("ifnull({0},0)+{1}", (context) -> {
                        context.expression(o.version())
                                .value(1);
                    });
                })
                .where(o -> o.id().eq(1))
                .executeRows();
        Assertions.assertTrue(rows > 0);
    }
上次编辑于:
贡献者: Hoysing,xuejiaming