Mybatis

1、使用mybatis先配置,生成pom.xm配置,手动添加resource插件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.9</version>
        <relativePath/>
    </parent>
    <groupId>com.zl</groupId>
    <artifactId>study-springboot-mysql</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <java.version>1.8</java.version>
    </properties>
 
    <dependencies>
        <!--web的起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--mybatis的起步依赖-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.3.0</version>
        </dependency>
        <!--mysql驱动依赖-->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!--测试-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
 
    <build>
        <!--手动添加resources插件-->
        <resources>
            <resource>
                <!--指定目录-->
                <directory>src/main/java</directory>
                <!--指定目录下的文件-->
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
 
        <!--plugins插件-->
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
 
</project>

2、添加application.yml的数据库源配置

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/yanhuo?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
    username: root
    password:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8


mybatis-plus:
  mapper-locations: classpath*:/mapper/*.xml
  #实体扫描,多个package用逗号或者分号分隔
  typeAliasesPackage: com.yanhuo.xo.model
  global-config:
    #数据库相关配置
    db-config:
      #主键类型
      id-type: ASSIGN_ID
    banner: false
  #原生配置
  configuration:
    map-underscore-to-camel-case: true
    cache-enabled: false
    call-setters-on-nulls: true
    jdbc-type-for-null: 'null'
  configuration-properties:
    prefix:
    blobType: BLOB
    boolValue: TRUE

多个Dao接口,可以在启动类使用@MapperScan(“basePackages= com.zl.dao ”),可是不能和@Mapper一起使用

如果需要使用xml写动态sql,我们需要在yml文件中,指定mapper.xml文件的位置

mybatis-plus:
mapper-locations: classpath*:/mapper/*.xml

需要在pom文件中,如开头手动添加resource的插件和配置

3、接下来就是对数据库的表进行CRUD

使用mybatis提供的接口BaseMapperMapper接口进行合适的操作

以及使用mybatis提供的接口IServiceServiceImpl实现类进行合适的操作

dao类继承BaseMapper的方法
@Mapper
public interface CommentDao extends BaseMapper<Comment> {

    /**
     * 得到所有回复消息
     * @param page
     * @param limit
     * @param uid
     * @return
     */
    List<CommentVo> getAllReplyComment(long page, long limit, String uid);
}
xml实现dao类中的方法
<mapper namespace="com.yanhuo.platform.dao.CommentDao">
    <select id="getAllReplyComment" resultType="com.yanhuo.xo.vo.CommentVo">
        SELECT
        c.id,
        c.content,
        c.create_date,
        c.uid,
        c.username,
        c.avatar,
        c.reply_id,
        c.reply_name,
        null as  reply_uid,
        null  as reply_content,
        i.id as mid,
        i.cover as cover

        FROM
        t_comment c
        JOIN t_img_detail i ON c.mid = i.id
        WHERE
        i.user_id = #{uid} and c.uid != #{uid}
        AND c.pid = 0

        union

        SELECT DISTINCT
        c.id,
        c.content,
        c.create_date,
        c.uid,
        c.username,
        c.avatar,
        c.reply_id,
        c.reply_name,
        s.uid as reply_uid,
        s.content AS reply_content,
        i.id as mid,
        i.cover as cover

        FROM
        t_comment c
        inner JOIN t_img_detail i ON c.mid = i.id

        left join   t_comment s ON c.reply_id = s.id

        WHERE
        i.user_id = #{uid} and c.uid != #{uid}
        AND c.pid != 0


        union

        SELECT
        s.id,
        s.content,
        s.create_date,
        s.uid,
        s.username,
        s.avatar,
        s.reply_id,
        s.reply_name,
        c.uid as reply_uid,
        c.content AS reply_content,
        i.id as mid,
        i.cover as cover
        FROM
        t_comment c

        left join  t_comment s ON  s.reply_id = c.id

        left join t_img_detail i on s.mid = i.id

        WHERE
        c.uid = #{uid} and s.uid != #{uid}

        order by
        create_date desc

         LIMIT ${(page-1)*limit},${limit};

    </select>
</mapper>
public interface BaseMapper<T> extends Mapper<T> {
    int insert(T entity);

    int deleteById(Serializable id);

    int deleteById(T entity);

    int deleteByMap(@Param("cm") Map<String, Object> columnMap);

    int delete(@Param("ew") Wrapper<T> queryWrapper);

    int deleteBatchIds(@Param("coll") Collection<?> idList);

    int updateById(@Param("et") T entity);

    int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);

    T selectById(Serializable id);

    List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);

    List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);

    default T selectOne(@Param("ew") Wrapper<T> queryWrapper) {
        List<T> ts = this.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(ts)) {
            if (ts.size() != 1) {
                throw ExceptionUtils.mpe("One record is expected, but the query result is multiple records", new Object[0]);
            } else {
                return ts.get(0);
            }
        } else {
            return null;
        }
    }

    default boolean exists(Wrapper<T> queryWrapper) {
        Long count = this.selectCount(queryWrapper);
        return null != count && count > 0L;
    }

    Long selectCount(@Param("ew") Wrapper<T> queryWrapper);

    List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);

    List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);

    List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);

    <P extends IPage<T>> P selectPage(P page, @Param("ew") Wrapper<T> queryWrapper);

    <P extends IPage<Map<String, Object>>> P selectMapsPage(P page, @Param("ew") Wrapper<T> queryWrapper);
}
接口Service类继承IService的方法
@Service
public class AgreeCollectServiceImpl extends ServiceImpl<AgreeCollectDao, AgreeCollect> implements AgreeCollectService 
{}
default boolean save(T entity) {
        return SqlHelper.retBool(this.getBaseMapper().insert(entity));
    }

    @Transactional(
        rollbackFor = {Exception.class}
    )
    default boolean saveBatch(Collection<T> entityList) {
        return this.saveBatch(entityList, 1000);
    }

    boolean saveBatch(Collection<T> entityList, int batchSize);

    @Transactional(
        rollbackFor = {Exception.class}
    )
    default boolean saveOrUpdateBatch(Collection<T> entityList) {
        return this.saveOrUpdateBatch(entityList, 1000);
    }

    boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);

    default boolean removeById(Serializable id) {
        return SqlHelper.retBool(this.getBaseMapper().deleteById(id));
    }

    default boolean removeById(Serializable id, boolean useFill) {
        throw new UnsupportedOperationException("不支持的方法!");
    }

    default boolean removeById(T entity) {
        return SqlHelper.retBool(this.getBaseMapper().deleteById(entity));
    }

    default boolean removeByMap(Map<String, Object> columnMap) {
        Assert.notEmpty(columnMap, "error: columnMap must not be empty", new Object[0]);
        return SqlHelper.retBool(this.getBaseMapper().deleteByMap(columnMap));
    }

    default boolean remove(Wrapper<T> queryWrapper) {
        return SqlHelper.retBool(this.getBaseMapper().delete(queryWrapper));
    }

    default boolean removeByIds(Collection<?> list) {
        return CollectionUtils.isEmpty(list) ? false : SqlHelper.retBool(this.getBaseMapper().deleteBatchIds(list));
    }

    @Transactional(
        rollbackFor = {Exception.class}
    )
    default boolean removeByIds(Collection<?> list, boolean useFill) {
        if (CollectionUtils.isEmpty(list)) {
            return false;
        } else {
            return useFill ? this.removeBatchByIds(list, true) : SqlHelper.retBool(this.getBaseMapper().deleteBatchIds(list));
        }
    }

    @Transactional(
        rollbackFor = {Exception.class}
    )
    default boolean removeBatchByIds(Collection<?> list) {
        return this.removeBatchByIds(list, 1000);
    }

    @Transactional(
        rollbackFor = {Exception.class}
    )
    default boolean removeBatchByIds(Collection<?> list, boolean useFill) {
        return this.removeBatchByIds(list, 1000, useFill);
    }

    default boolean removeBatchByIds(Collection<?> list, int batchSize) {
        throw new UnsupportedOperationException("不支持的方法!");
    }

    default boolean removeBatchByIds(Collection<?> list, int batchSize, boolean useFill) {
        throw new UnsupportedOperationException("不支持的方法!");
    }

    default boolean updateById(T entity) {
        return SqlHelper.retBool(this.getBaseMapper().updateById(entity));
    }

    default boolean update(Wrapper<T> updateWrapper) {
        return this.update((Object)null, updateWrapper);
    }

    default boolean update(T entity, Wrapper<T> updateWrapper) {
        return SqlHelper.retBool(this.getBaseMapper().update(entity, updateWrapper));
    }

    @Transactional(
        rollbackFor = {Exception.class}
    )
    default boolean updateBatchById(Collection<T> entityList) {
        return this.updateBatchById(entityList, 1000);
    }

    boolean updateBatchById(Collection<T> entityList, int batchSize);

    boolean saveOrUpdate(T entity);

    default T getById(Serializable id) {
        return this.getBaseMapper().selectById(id);
    }

    default List<T> listByIds(Collection<? extends Serializable> idList) {
        return this.getBaseMapper().selectBatchIds(idList);
    }

    default List<T> listByMap(Map<String, Object> columnMap) {
        return this.getBaseMapper().selectByMap(columnMap);
    }

    default T getOne(Wrapper<T> queryWrapper) {
        return this.getOne(queryWrapper, true);
    }

    T getOne(Wrapper<T> queryWrapper, boolean throwEx);

    Map<String, Object> getMap(Wrapper<T> queryWrapper);

    <V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

    default long count() {
        return this.count(Wrappers.emptyWrapper());
    }

    default long count(Wrapper<T> queryWrapper) {
        return SqlHelper.retCount(this.getBaseMapper().selectCount(queryWrapper));
    }

    default List<T> list(Wrapper<T> queryWrapper) {
        return this.getBaseMapper().selectList(queryWrapper);
    }

    default List<T> list() {
        return this.list(Wrappers.emptyWrapper());
    }

    default <E extends IPage<T>> E page(E page, Wrapper<T> queryWrapper) {
        return this.getBaseMapper().selectPage(page, queryWrapper);
    }

    default <E extends IPage<T>> E page(E page) {
        return this.page(page, Wrappers.emptyWrapper());
    }

    default List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper) {
        return this.getBaseMapper().selectMaps(queryWrapper);
    }

    default List<Map<String, Object>> listMaps() {
        return this.listMaps(Wrappers.emptyWrapper());
    }

    default List<Object> listObjs() {
        return this.listObjs(Function.identity());
    }

例子:

简单的就用new QueryWrapper() 直接查询了,不用写入xml,复杂的才要xml

@Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAlbum(String id, String uid) {
        //得到当前专辑下的所有图片
        List<AlbumImgRelation> albumImgRelationEntityList = albumImgRelationService.list(new QueryWrapper<AlbumImgRelation>().eq("aid", id));
        List<String> idList = albumImgRelationEntityList.stream().map(e -> String.valueOf(e.getMid())).collect(Collectors.toList());

        String albumStateKey = PlatformConstant.ALBUM_STATE + id;
        redisUtils.delete(albumStateKey);

        imgDetailService.deleteImgs(idList, uid);
        this.removeById(id);
    }

4、实例类

dao类和service类和Impl

Dao接口是mapper映射操作
@Service
public class ChatServiceImpl implements ChatService {

    @Autowired
    MessageDao messageDao;
    
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addChatRecord(MessageDTO messageDTO) {
        //往数据库里面添加记录,
        Message messageEntity = ConvertUtils.sourceToTarget(messageDTO, Message.class);
        messageEntity.setTime(String.valueOf(System.currentTimeMillis()));
        messageDao.insert(messageEntity);
        `````
    }
    
数据库表名的类是数据库中表数据的映像到JAVA中的对象类
@Data
@TableName("t_message")
public class Message extends BaseEntity{

}

@Data
public abstract class BaseEntity implements Serializable {
    /**
     * id
     */
    @TableId
    private Long id;
    /**
     * 创建者
     */
    @TableField(fill = FieldFill.INSERT)
    private Long  creator;
    /**
     * 创建时间
     */
    @TableField(fill = FieldFill.INSERT)
    private Date createDate;
}

其中

``@TableField(fill = FieldFill.INSERT)` 是 MyBatis-Plus 框架中的注解,用于指定数据库字段在插入操作时的填充方式。这个注解通常与实体类中的字段一起使用。

  • @TableField 注解用于标识数据库表字段与实体类属性的映射关系。
  • fill 参数指定了填充策略,FieldFill.INSERT 表示在执行插入操作时填充该字段。

这个注解的作用是在执行插入操作时自动填充数据库表的相应字段,通常用于设置数据库表的创建时间或者创建者等信息,以简化开发者的操作。

@TableField 是 MyBatis-Plus 中的一个注解,用于标识实体类字段与数据库表字段的映射关系,并提供了一些属性来配置该映射关系的细节。

常用的属性包括:

  1. value:指定该字段映射的数据库表字段名。如果实体类字段名与数据库表字段名相同,则可以省略该属性。

    @TableField("user_name")
    private String userName;
    
  2. exist:指定该字段是否为数据库表中的实际字段。当设置为 false 时,表示该字段只在业务逻辑中使用,而不对应数据库表中的实际字段,默认为 true。

    @TableField(value = "is_deleted", exist = false)
    private Boolean deleted;
    
  3. el:指定一个 EL 表达式,用于动态计算该字段的值。

    @TableField(el = "userType == 'ADMIN' ? 'Y' : 'N'")
    private String isAdmin;
    
  4. fill:指定在插入或更新操作时,自动填充该字段的策略。

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    
    @TableField(fill = FieldFill.UPDATE)
    private LocalDateTime updateTime;
    
  5. condition:指定更新操作时,仅当满足指定条件时才更新该字段的值。

    @TableField(value = "last_modified", condition = "%s != null")
    private LocalDateTime lastModified;
    

这些属性可以根据实际业务需求进行组合使用,以实现灵活的映射配置和字段行为控制。

如果实体类中的字段不是对应本表的字段,而是对应其他表的字段,可以通过 @TableField 注解的 value 属性来指定该字段在本表中的映射字段名。这样,在查询或操作本表时,就可以使用该字段,而实际操作的是其他表的数据。

举个例子,假设有两个表 userrole,在 user 表中有一个字段 role_id,用来表示用户的角色,在 role 表中有一个字段 role_name,表示角色的名称。如果在 User 实体类中需要使用角色名称,可以这样配置:

javaCopy Codepublic class User {
    private Long id;
    
    @TableField(value = "role_name", exist = false)
    private String roleName;  // 该字段不是本表字段,而是与 role 表关联的字段
    
    // 其他字段和方法省略
}

在上述配置中,roleName 字段并不是 user 表中的实际字段,而是表示用户角色的名称,通过 @TableField 注解的 value 属性指定了在 user 表中的映射字段名为 role_name。这样,当查询 User 对象时,可以通过 roleName 字段获取用户对应的角色名称,虽然实际操作的是 role 表中的数据。

@TableId 是 MyBatis-Plus 中的一个注解,用于标识实体类中的主键字段。它的作用是告诉 MyBatis-Plus 这个字段是数据库表的主键,以便在执行 CRUD 操作时进行识别和处理。

常用的属性包括:

  1. value:指定主键字段的名称,如果实体类中的字段名与数据库表中的主键字段名相同,则可以省略该属性。

    javaCopy Code@TableId("user_id")
    private Long id;
    
  2. type:指定主键生成策略,常见的有 AUTO、INPUT、ID_WORKER、ID_WORKER_STR 等,根据实际情况选择合适的主键生成策略。

    • AUTO:数据库自增,适用于支持自增主键的数据库,如 MySQL、SQL Server 等。
    • INPUT:手动输入,需要在插入数据时手动设置主键值。
    • ID_WORKER:数字类型的全局唯一 ID,使用雪花算法生成,适用于分布式环境。
    • ID_WORKER_STR:字符串类型的全局唯一 ID,同样使用雪花算法生成。
    javaCopy Code@TableId(value = "id", type = IdType.AUTO)
    private Long id;
    
  3. exist:指定该字段是否为数据库表中的实际字段。当设置为 false 时,表示该字段只在业务逻辑中使用,而不对应数据库表中的实际字段,默认为 true。

    javaCopy Code@TableId(value = "id", exist = false)
    private Long id;
    

通过 @TableId 注解标识主键字段,可以使 MyBatis-Plus 自动生成符合预期的主键值,并在执行插入、更新、删除等操作时正确识别主键字段,从而简化开发工作。`

DTO类是数据库数据转换为JAVA对象后,用于校验和操作的对象类
@Data
public class AgreeCollectDTO implements Serializable {

    @ApiModelProperty(value = "当前点赞的用户id")
    @NotNull(message = "uid不能为空", groups = DefaultGroup.class)
    private Long uid;

    @ApiModelProperty(value = "点赞的类型id")
    @NotNull(message = "点赞id不能为空", groups = DefaultGroup.class)
    private Long agreeCollectId;

    @ApiModelProperty(value = "点赞图片或评论发布的用户id")
    @NotNull(message = "给他人点赞id不能为空", groups = DefaultGroup.class)
    private Long agreeCollectUid;


    @ApiModelProperty(value = "0代表点赞评论,1代表点赞图片,2代表收藏图片,3是收藏专辑")
    @InValues(vals = {0, 1, 2, 3}, groups = DefaultGroup.class)
    private Integer type;
}

对比原来数据库中的源类

@Data
@ApiModel(description = "点赞收藏")
@TableName("t_agree_collect")
public class AgreeCollect extends BaseEntity {

    private Long uid;

    private Long agreeCollectId;

    private Long agreeCollectUid;

    private Integer type;

}
VO类是返回给前端的JSON类,所以内容经过整合了,内容可能包括表名类和相关的表名关系类及其他相关的类,可以对比上面的DTO类和未修改的源类
 public CommentVo addComment(CommentDTO commentDTO){}
@Data
@Accessors(chain = true)
public class AgreeCollectVo implements Serializable {

    private Long aid;

    private Long mid;

    private String cover;

    private Long uid;

    private String username;

    private String avatar;

    private String content;

    private String name;

    private Integer count;

    /**
     * 图片数量
     */
    private Long imgCount;

    /**
     * 收藏数量
     */
    private Long collectionCount;

    // 0是评论,1是图片,2专辑
    private Integer type;

    private Date createDate;

}
@Mapper
public interface AgreeCollectDao extends BaseMapper<AgreeCollect> {
}

public interface AgreeCollectService extends IService<AgreeCollect> {
}

@Service
public class AgreeCollectServiceImpl extends ServiceImpl<AgreeCollectDao, AgreeCollect> implements AgreeCollectService {
}

//因为继承了DAO类,使用可以通过this引用 直接使用DAO类中BaseMapper接口的方法
可以使用save、insert、
 this.getOne(new QueryWrapper<AgreeCollect>().eq("name","name").like("name","%丽%"));
等等

Impl 是实现类
public interface AgreeCollectService extends IService<AgreeCollect>{}
@Service
public class AgreeCollectServiceImpl extends ServiceImpl<AgreeCollectDao, AgreeCollect> implements AgreeCollectService

在Controller中可以之间使用Serviced 接口,因为子类Impl的Bean会注入AgreeCollectService的@Autowired的变量中

@Autowired
    private AgreeCollectService agreeCollectService;


5、实例类之间转换方法

BeanUtils.copyProperties 是 Apache Commons BeanUtils 库中的一个方法,用于将一个 JavaBean 的属性值复制到另一个 JavaBean 中。这个方法通常用于简化对象之间的属性复制工作,比如将一个 DTO(Data Transfer Object)对象的属性复制到一个持久化实体对象中。

具体用法如下:

javaCopy Code// 导入需要的包
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;

// 复制属性
BeanUtils.copyProperties(destBean, origBean);

在这个方法中,destBean 是目标对象,origBean 是源对象,该方法会自动匹配两个对象中对应属性名的值,并进行复制。需要注意的是,BeanUtils.copyProperties 方法只复制属性名和类型相同的属性,不会复制类型不同的属性,也不会进行深度复制。

需要留意的是,在使用 BeanUtils.copyProperties 方法时,如果两个对象中存在同名但不同类型的属性,会抛出 NoSuchMethodException 异常,因此在使用之前需要确保源对象和目标对象的属性类型一致。

public static <T> T sourceToTarget(Object source, Class<T> target){
        if(source == null){
            return null;
        }
        T targetObject = null;
        try {
            targetObject = target.newInstance();
            BeanUtils.copyProperties(source, targetObject);
        } catch (Exception e) {
            logger.error("convert error ", e);
        }

        return targetObject;
    }


public void saveAlbum(AlbumDTO albumDTO) {
        Album albumEntity = ConvertUtils.sourceToTarget(albumDTO, Album.class);
        this.save(albumEntity);
    }

@Data//隐式完成setter和getter、toString
@ApiModel(value = "专辑")
public class AlbumDTO implements Serializable {
	private static final long serialVersionUID = 1L;

	@ApiModelProperty(value = "专辑id")
	private Long id;

	@ApiModelProperty(value = "专辑名称")
	@NotBlank(message = "内容不能为空", groups = DefaultGroup.class)
	private String name;

	@ApiModelProperty(value = "专辑发布的用户id")
	@NotNull(message = "用户id不能为空", groups = DefaultGroup.class)
	private Long uid;

	@ApiModelProperty(value = "专辑封面")
	private String cover;

	@ApiModelProperty(value = "专辑排序")
	private Integer sort;
}

@Data
@TableName("t_album")
public class Album extends BaseEntity {
    /**
     *专辑名称
     */
    private String name;
    /**
     * 专辑发布的用户id
     */
    private Long uid;
    /**
     * 专辑封面
     */
    private String cover;
    /**
     * 专辑排序
     */
    private Integer sort;


    /**
     * 图片数量
     */
    private Long imgCount;

    /**
     * 收藏数量
     */
    private Long collectionCount;

    /**
     * 修改用户
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updater;
    /**
     * 修改时间
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateDate;
}

6、事务支持

事务支持(Transaction Support)是指在数据库管理系统中,对于一组相关的数据库操作,确保这组操作要么全部成功执行,要么全部失败回滚的机制。它是保证数据库的一致性和可靠性的重要手段。

在数据库中,事务是由一系列的数据库操作组成的逻辑单位。事务支持提供了以下几个关键特性:

  1. 原子性(Atomicity):事务中的所有操作要么全部执行成功,要么全部失败回滚。如果一个操作失败,那么之前已经执行的操作都会被撤销,数据库返回到事务开始前的状态,保证数据库的一致性。
  2. 一致性(Consistency):事务的执行不会破坏数据库的完整性约束条件,即使在并发执行的情况下也能保证数据的一致性。
  3. 隔离性(Isolation):并发执行的事务之间应该相互隔离,每个事务的执行应当与其他事务的执行相互独立,互不干扰。事务的隔离性能够避免并发执行时可能出现的问题,如脏读、不可重复读、幻读等。
  4. 持久性(Durability):一旦事务提交成功,其所做的修改将永久保存在数据库中,即使发生系统故障或重启,也不会丢失。

事务支持的主要目的是确保数据库的数据一致性和可靠性。通过将一组相关的操作封装在事务中,可以保证这些操作要么全部成功执行,要么全部回滚,从而避免了因为部分操作失败而导致数据库处于不一致的状态。同时,事务支持还能够提高数据库的并发性能,允许多个事务同时执行而互不干扰。

Spring框架中的事务:

(1)使用管理事务的对象: 事务管理器(接口, 接口有很多的实现类)

例:使用Jdbc或mybatis访问数据库,使用的事务管理器:DataSourceTransactionManager

(2)声明式事务: 在xml配置文件或者使用注解说明事务控制的内容

控制事务: 隔离级别,传播行为, 超时时间等

(3)事务处理方式:

①Spring框架中的@Transactional;

②aspectj框架可以在xml配置文件中,声明事务控制的内容;

SpringBoot使用事务非常简单,底层依然采用的是 Spring 本身提供的事务管理

①在业务方法的上面加入@Transactional , 加入注解后,方法有事务功能了。

②在主启动类的上面 ,加入@EnableTransactionManager,开启事务支持。

如果只是springboot添加事务功能,只可以在服务器回滚事务,在mysql数据库中却可以回滚,所以需要在注解中添加rollbackFor=Exception.class,使得数据库也会回滚

@Override
    @Transactional(rollbackFor = Exception.class)
    public CommentVo addComment(CommentDTO commentDTO){}

注:只加上@Transactional也能完成事务的功能,对于@EnableTransactionManager建议也加上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值