Day23:事务管理、显示评论、添加评论

事务管理

事务的定义

什么是事务

  • 事务是由N步数据库操作序列组成的逻辑执行单元,这系列操作要么全执行,要么全放弃执行。

事务的特性(ACID)

  • 原子性(Atomicity):事务是应用中不可再分的最小执行体(事务中部分执行失败就会回滚 。
  • 一致性(Consistency):事务执行的结果,须使数据从一个一致性状态,变为另一个一致性状态。
  • **隔离性(Isolation)😗*各个事务的执行互不干扰,任何事务的内部操作对其他的事务都是隔离的。
  • 持久性(Durability):事务一旦提交,对数据所做的任何改变都要记录到永久存储器中。

事务的隔离性

常见的并发异常

  • 第一类丢失更新、第二类丢失更新。
  • 脏读、不可重复读、幻读。

常见的隔离级别 (从低到高)

  • Read Uncommitted:读取未提交的数据。
  • Read Committed:读取已提交的数据。
  • Repeatable Read:可重复读。
  • Serializable:串行化。(可以解决所有的问题,但需要加锁降低数据库性能)

第一类丢失更新

image

(事务1的回滚导致事务2的数据更新失败)

第二类丢失更新

image

(事务1和事务2最终结果都是11,事务2不能接受)

脏读

image

(实际上事务2读到的11,实际上N已经是10了)

不可重复读

image

(事务2并没有对N变动,但先后结果不一样,查询单行数据导致不一致)

幻读

image

(查询多行数据导致不一致)

不用的处理方式对数据安全的影响

image

(一般中间两种比较适合)

数据库保证事务的实现机制

  • 悲观锁(数据库)
    • 共享锁(S锁):事务A对某数据加了共享锁后,其他事务只能对该数据加共享锁,但不能加排他锁。
    • 排他锁(X锁):事务A对某数据加了排他锁后,其他事务对该数据既不能加共享锁,也不能加排他锁。
  • 乐观锁(自定义)
    • 版本号、时间戳等
    • 在更新数据前,检查版本号是否发生变化。若变化则取消本次更新,否则就更新数据(版本号+1)。

Spring事务管理

  • 声明式事务(简单,常用的项目设置)
    • 通过XML配置,声明某方法的事务特征。
    • 通过注解,声明某方法的事务特征。
  • 编程式事务(适合数据库中很多操作,只需要控制部分操作)
    • 通过 TransactionTemplate 管理事务,并通过它执行数据库的操作。

示例

  • 需求:一个用户自动注册完自动发送帖子
  • 如果存在事务,整个会原子执行,报错后会回滚,也就是用户和帖子不会被创建在数据库中

声明式事务(常用,简单)

@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
public Object save1(){
    User user = new User();
    user.setUsername("test");
    user.setSalt("abc");
    user.setPassword(CommunityUtil.md5("123" + user.getSalt()));
    user.setEmail("742uu12@qq.com");
    user.setHeaderUrl("http://www.nowcoder.com/101.png");
    user.setCreateTime(new Date());
    userMapper.insertUser(user);

    //发布帖子
    DiscussPost post = new DiscussPost();
    post.setUserId(user.getId());
    post.setTitle("hello");
    post.setContent("新人报道");
    post.setCreateTime(new Date());
    discussPostMapper.insertDiscussPost(post);

    Integer.valueOf("abc");
    return "ok";
}

//A调B,两者都有事务

//(REQUIRED):B支持当前事务(外部事务A),如果不存在则创建新事务

//(REQUIRES_NEW):B创建一个新事务,并且暂停当前事务(外部事务A)

//(NESTED):B如果当前存在事务(外部事务A),则嵌套在该事务中执行(有独立的提交和回滚),否则和REQUIRED一样

  • 使用Transactional注解,isolation规定策略,propagation规定传播方式;
  • 故意写一个报错的句子 Integer.valueOf(“abc”);

使用TransactionTemplate

public String save2(){
    transactionTemplate.setIsolationLevel(TransactionTemplate.ISOLATION_READ_COMMITTED);
    transactionTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRED);
    String result = transactionTemplate.execute(new TransactionCallback<String>() {
        @Override
        public String doInTransaction(org.springframework.transaction.TransactionStatus transactionStatus) {
            User user = new User();
            user.setUsername("test");
            user.setSalt("abc");
            user.setPassword(CommunityUtil.md5("123" + user.getSalt()));
            user.setEmail("742uu12@qq.com");
            user.setHeaderUrl("http://www.nowcoder.com/101.png");
            user.setCreateTime(new Date());
            userMapper.insertUser(user);

            //发布帖子
            DiscussPost post = new DiscussPost();
            post.setUserId(user.getId());
            post.setTitle("hello");
            post.setContent("新人报道");
            post.setCreateTime(new Date());
            discussPostMapper.insertDiscussPost(post);

            return "ok";
        }
    });

    return result;
}

显示评论

  • 数据层
    • 根据实体查询一页评论数据。
    • 根据实体查询评论的数量。
  • 业务层
    • 处理查询评论的业务。
    • 处理查询评论数量的业务。
  • 表现层
    • 显示帖子详情数据时,
    • 同时显示该帖子所有的评论数据。

数据层DAO

  1. 编写Comment实体类:
package com.newcoder.community.entity;

public class Comment {
    int id;
    int userId;
    int entityType;
    int entityId;
    int targetId;
    String content;
    String status;
    String createTime;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public int getEntityType() {
        return entityType;
    }

    public void setEntityType(int entityType) {
        this.entityType = entityType;
    }

    public int getEntityId() {
        return entityId;
    }

    public void setEntityId(int entityId) {
        this.entityId = entityId;
    }

    public int getTargetId() {
        return targetId;
    }

    public void setTargetId(int targetId) {
        this.targetId = targetId;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getCreateTime() {
        return createTime;
    }

    public void setCreateTime(String createTime) {
        this.createTime = createTime;
    }

    @Override
    public String toString() {
        return "Comment{" +
                "id=" + id +
                ", userId=" + userId +
                ", entityType=" + entityType +
                ", entityId=" + entityId +
                ", targetId=" + targetId +
                ", content='" + content + '\'' +
                ", status='" + status + '\'' +
                ", createTime='" + createTime + '\'' +
                '}';
    }
}

  1. 定义CommentMapper接口
@Mapper
public interface CommentMapper {
    List<Comment> selectCommentsByEntity(int entityType, int entityId, int offset,int limit);
    int selectCountByEntity(int entityType, int entityId);

}
  1. 编写comment-mapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.newcoder.community.dao.CommentMapper">
    <sql id="selectFields">
        id
        , user_id, entity_type, entity_id, target_id, content, status, create_time
    </sql>

    <select id="selectCommentByEntity" resultType="Comment">
        select
        <include refid="selectFields"/>
        from comment
        where entity_type = #{entityType} and entity_id = #{entityId}
        order by create_time desc
    </select>

    <select id="selectCommentCount" resultType="int">
        select count(id)
        from comment
        where entity_type = #{entityType}
          and entity_id = #{entityId}mapper >
    </select>

</mapper>

业务层

  1. 编写CommentService类
@Service
public class CommentService {
    @Autowired
    private CommentMapper commentMapper;

    public List<Comment> findCommentsByEntity(int entityType, int entityId, int offset, int limit){
        return commentMapper.selectCommentsByEntity(entityType,entityId,offset,limit);
    }

    public int findCommentCount(int entityType, int entityId){
        return commentMapper.selectCountByEntity(entityType,entityId);
    }


}

Controller层

修改之前的getDiscussPost函数:

@RequestMapping(path = "/detail/{discussPostId}", method = RequestMethod.GET)
    public String getDiscussPost(@PathVariable(name = "discussPostId") int discussPostId, Model model, Page page) {
        DiscussPost post = discussPostService.findDiscussPostById(discussPostId);
        model.addAttribute("post", post);
        //帖子的作者
        User user = userService.findUserById(post.getUserId());
        model.addAttribute("user", user);

        //评论分页信息
        page.setLimit(5);
        page.setPath("/discuss/detail/" + discussPostId);
        page.setRows(post.getCommentCount());//直接从帖子中取

        List<Comment> commentList = commentService.findCommentsByEntity(ENTITY_TYPE_POST, post.getId(), page.getOffset(), page.getLimit());
        //遍历集合,将每个评论的其他信息查出来(这里嵌套是难点,之后可以在面试上说)
        List<Map<String, Object>> commentVoList = new ArrayList<>();
        if(commentList != null){
            for(Comment comment : commentList){
                //评论Vo
                Map<String, Object> commentVo = new java.util.HashMap<>();
                //评论
                commentVo.put("comment",comment);
                //作者
                commentVo.put("user",userService.findUserById(comment.getUserId()));

                //回复列表(评论的评论)
                List<Comment> replyList = commentService.findCommentsByEntity(ENTITY_TYPE_COMMENT,comment.getId(),0,Integer.MAX_VALUE);
                List<Map<String,Object>> replyVoList = new ArrayList<>();
                if(replyList != null){
                    for(Comment reply : replyList){
                        Map<String,Object> replyVo = new java.util.HashMap<>();
                        //回复
                        replyVo.put("reply",reply);
                        //作者
                        replyVo.put("user",userService.findUserById(reply.getUserId()));
                        //回复目标
                        User target = reply.getTargetId() == 0 ? null : userService.findUserById(reply.getTargetId());
                        replyVo.put("target",target);
                        replyVoList.add(replyVo);
                    }
                }
                commentVo.put("replys",replyVoList);
                //回复数量
                int replyCount = commentService.findCommentCount(ENTITY_TYPE_COMMENT,comment.getId());
                commentVo.put("replyCount",replyCount);
                commentVoList.add(commentVo);
            }
        }
        //将评论Vo列表传给前端
        model.addAttribute("comments",commentVoList);
        return "/site/discuss-detail";
    }

方法有点长,从14行开始,首先设置分页信息(只有评论分页,评论的评论不分页)

然后查询所有评论,接着查询评论的评论,都加入hashmap中。

修改index.html

image

修改discuss-detail.html

这里太复杂了,直接把html附上:

注意这里的分页可以复用首页的分页逻辑。

  • 评论显示分页:复用index.html中的th:fragment=“pagination”
<nav class="mt-5" th:replace="index::pagination">
					<ul class="pagination justify-content-center">
						<li class="page-item"><a class="page-link" href="#">首页</a></li>
						<li class="page-item disabled"><a class="page-link" href="#">上一页</a></li>
						<li class="page-item active"><a class="page-link" href="#">1</a></li>
						<li class="page-item"><a class="page-link" href="#">2</a></li>
						<li class="page-item"><a class="page-link" href="#">3</a></li>
						<li class="page-item"><a class="page-link" href="#">4</a></li>
						<li class="page-item"><a class="page-link" href="#">5</a></li>
						<li class="page-item"><a class="page-link" href="#">下一页</a></li>
						<li class="page-item"><a class="page-link" href="#">末页</a></li>
					</ul>
				</nav>		

添加评论

数据层DAO

  1. 在CommentMapper中添加insert帖子接口:
    int insertComment(Comment comment);
  • 返回值为什么是int:

在MyBatis中,insert方法通常返回一个int类型的值,这个值表示的是插入操作影响的行数。如果插入成功,这个值应该是1(因为插入一条数据影响一行);如果插入失败,这个值可能是0(没有行被影响)。这样,开发者可以通过检查这个返回值来判断插入操作是否成功。

  1. 修改comment-Mapper,修改sql语句:
 <sql id="insertFields">
        user_id, entity_type, entity_id, target_id, content, status, create_time
    </sql>

 <insert id="insertComment" parameterType="Comment">
        insert into comment (<include refid="insertFields"></include>)
        values (#{userId}, #{entityType}, #{entityId}, #{targetId}, #{content}, #{status}, #{createTime})
    </insert>


  1. 修改postmapper更新评论数量
int updateCommentCount(int id, int commentCount);
  1. 修改postmapper填写sql
    <update id="updateCommentCount">
        update discuss_post
        set comment_count = #{commentCount}
        where id = #{id}
    </update>

业务层

  1. DiscussPostService:
public int updateCommentCount(int id, int commentCount) {
        return discussPostMapper.updateCommentCount(id, commentCount);
    }
  1. CommentService(引入事务管理,重点!!!)
@Transactional(isolation = Isolation.READ_COMMITTED,propagation = Propagation.REQUIRED)
public int addComment(Comment comment){
    if(comment == null){
        throw new IllegalArgumentException("参数不能为空");
    }
    //转义HTML标记和过滤敏感词
    comment.setContent(HtmlUtils.htmlEscape(comment.getContent()));
    comment.setContent(sensitiveFilter.filter(comment.getContent()));

    int rows = commentMapper.insertComment(comment);

    //更新帖子评论数量(过滤楼中楼)
    if(comment.getEntityType() == ENTITY_TYPE_POST){
        int count = commentMapper.selectCountByEntity(comment.getEntityType(),comment.getEntityId());
        discussPostService.updateCommentCount(comment.getEntityId(), count);
    }
    
    return rows;
}

过滤敏感词、识别是帖子的评论而不是楼中楼,更新评论;

Controller层

添加一个新的CommentController:

@Controller
@RequestMapping("/comment")
public class CommentController {
    @Autowired
    private CommentService commentService;

    @Autowired
    private HostHolder hostHolder;

    @RequestMapping(path="add/{discussPostId}",method = RequestMethod.POST)
    public String addComment(@PathVariable("discussPostId") int discussPostId, Comment comment, Model model) {
        comment.setUserId(hostHolder.getUser().getId());
        comment.setStatus(0);
        comment.setCreateTime(new Date());

        commentService.addComment(comment);
        return "redirect:/discuss/detail/" + discussPostId;
    }
}
  • 想要重定向回原页面,故用@PathVariable取id好拼接url。

修改模板

修改的是site/discuss-post.html

  1. 修改评论输入框
<div class="container mt-3">
    <form class="replyform" method="post" th:action="@{|/comment/add/${post.id}|}">
        <p class="mt-3">
            <a name="replyform"></a>
            <textarea placeholder="在这里畅所欲言你的看法吧!" name="content"></textarea>
            <input type="hidden" name="entityType" value="1"/>
            <input type="hidden" name="entityId" th:value="${post.id}"/>
        </p>
        <p class="text-right">
            <button type="submit" class="btn btn-primary btn-sm">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</button>
        </p>
    </form>
</div>

在您的CommentController中,您使用了Comment对象来接收表单提交的数据。Spring MVC会自动将请求参数绑定到Comment对象的属性上,这是通过参数名和Comment对象属性名的匹配来实现的。因此,content表单元素的值会被自动绑定到Comment对象的content属性上。

image

  1. 修改楼中楼输入框:(就是回复评论的框)
<li class="pb-3 pt-3">
    <form method="post" th:action="@{|/comment/add/${post.id}|}">
        <div>
            <input type="text" class="input-size" name="content" placeholder="请输入你的观点"/>
            <input type="hidden" name="entityType" value="2"/>
            <input type="hidden" name="entityId" th:value="${cvo.comment.id}"/>
        </div>
        <div class="text-right mt-2">
            <button type="button" class="btn btn-primary btn-sm" onclick="#">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</button>
        </div>
    </form>
</li>

image

  1. 修改楼中楼中楼的框(就是回复评论的评论的框)
<div th:id="|huifu-${rvoStat.count}|" class="mt-4 collapse">
    <form method="post" th:action="@{|/comment/add/${post.id}|}">
        <div>
            <input type="text" class="input-size" name = "content" th:placeholder="|回复${rvo.user.username}|"/>
            <input type="hidden" name="entityType" value="2"/>
            <input type="hidden" name="entityId" th:value="${cvo.comment.id}"/>
            <input type="hidden" name="targetId" th:value="${rvo.user.id}"/>
        </div>
        <div class="text-right mt-2">
            <button type="submit" class="btn btn-primary btn-sm" onclick="#">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</button>
        </div>
    </form>
</div>

image

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/494417.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AWS基础网络产品及协同架构-Networking

简介 一个完整的AWS网络架构图&#xff0c;包含了如下能力&#xff1a; Users (用户): 表示使用AWS服务的用户或系统。 SaaS (软件即服务): 表示在AWS上运行的软件服务&#xff0c;如企业微信可能作为SaaS提供。 example.com?: 这可能是一个示例域名&#xff0c;用于展示如何…

[2021]Zookeeper getAcl命令未授权访问漏洞概述与解决

今天在漏洞扫描的时候蹦出来一个zookeeper的漏洞问题&#xff0c;即使是非zookeeper的节点&#xff0c;或者是非集群内部节点&#xff0c;也可以通过nc扫描2181端口&#xff0c;获取极多的zk信息。关于漏洞的详细描述参考apache zookeeper官方概述&#xff1a;CVE-2018-8012: A…

KPCA-GWO-LSSVM,基于KPCA核主成分分析优化灰狼优化算法GWO结合最小二乘支持向量机LSSVM回归预测

基于KPCA核主成分分析优化灰狼优化算法&#xff08;KPCA-GWO&#xff09;结合最小二乘支持向量机&#xff08;LSSVM&#xff09;回归是一种用于回归分析的混合优化算法。下面我将简要介绍这个方法的步骤&#xff1a; 核主成分分析&#xff08;KPCA&#xff09;&#xff1a; KPC…

小米HyperOS 澎湃os机型免答题 免社区等级 秒接bl锁操作步骤解析

小米机型解锁bl 绕过社区等级5才可以解锁的限制的教程_没有五级社区怎么解锁bl-CSDN博客 上次解析了小米有些出厂不是HyperOS系统的机型绕社区等级接bl锁的操作。目前有更新出厂为HyperOS系统的机型免社区登录等级限制 免答题解锁bl的操作。而且有网友在米14 平板6sp k70这些新…

解决kubesphere流水线docker登陆错误http: server gave HTTP response to HTTPS client

kubesphere DevOps流水线中&#xff0c;在登录私有的harbor仓库时&#xff0c;报以下错误 docker login 111.230.19.120:80 -u admin -p test123. WARNING! Using --password via the CLI is insecure. Use --password-stdin. Error response from daemon: Get "https://…

Android JNI SO库和对应的CPU架构详解

Android JNI SO库和对应的CPU架构详解 文章目录 Android JNI SO库和对应的CPU架构详解一、前言二、Android CPU架构1、Android系统支持的CPU架构2、如查查看手机的CPU架构&#xff08;1&#xff09;Android13 大屏AML厂商的cpu信息&#xff1a;&#xff08;2&#xff09;电脑An…

前缀和算法(1)

目录 一维前缀和[模板] 一、题目描述 二、思路解析 三、代码 二维前缀和[模板] 一、题目描述 二、思路解析 三、代码 724.寻找数组的中心下标 一、题目描述 二、思路解析 三、代码 238.除自身以外数组的乘积 一、题目描述 二、思路解析 三、代码 一维前缀和[模…

数据结构——二叉搜索树详解

一、二叉搜索树定义 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树: 1.非空左子树上所有节点的值都小于根节点的值。 2.非空右子树上所有节点的值都大于根节点的值。 3.左右子树也都为二叉搜索树。 如下图所示&#xff1a…

上位机图像处理和嵌入式模块部署(qmacvisual区域提取)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 在图像处理中&#xff0c;有两部分比较重要&#xff0c;一个是区域分割&#xff0c;一个是区域提取。区域分割&#xff0c;比较好理解&#xff0c;…

IDEA的使用(概念,安装,配置,)以及什么是字符集,模版

目录 Intellij IDEA IDE的概念 IntelliJ IDEA的安装 IntelliJ IDEA的使用 基本配置 JDK配置 创建Module 基本用法 字体配置 主题配置 字符集 设置IDEA默认字符集 注释模板 字符集 字符集简介 常见字符集 Intellij IDEA 我们不可能一直使用记事本之类变成&#…

BUG定位---一起学习吧之测试

判断一个BUG是前端还是后端的&#xff0c;通常需要根据BUG的具体表现、发生的环境以及相关的技术栈来进行分析。以下是一些常用的判断方法&#xff1a; 错误发生的位置&#xff1a; 如果BUG涉及的是页面的布局、样式、交互效果等&#xff0c;那么很可能是前端的BUG。如果BUG与…

计算机网络:物理层 - 信道复用

计算机网络&#xff1a;物理层 - 信道复用 频分复用时分复用统计时分复用波分复用码分复用 计算机网络中&#xff0c;用户之间通过信道进行通信&#xff0c;但是信道是有限的&#xff0c;想要提高网络的效率&#xff0c;就需要提高信道的利用效率。因此计算机网络中普遍采用信道…

python学习12:python中的字符串格式化-数字精度控制

python中的字符串格式化-数字精度控制 1.使用辅助符号"m.n"来进行数据的宽度和精度的控制 m,控制宽度&#xff0c;要求是数字&#xff08;一般是很少使用的&#xff09;&#xff0c;设置的宽度小于数字自身&#xff0c;不生效 n,控制小数点精度&#xff0c;要求是数…

PASSL代码解读[01] readme

介绍 PASSL 是一个基于 PaddlePaddle 的视觉库&#xff0c;用于使用 PaddlePaddle 进行最先进的视觉自监督学习研究。PASSL旨在加速自监督学习的研究周期&#xff1a;从设计一个新的自监督任务到评估所学的表征。 PASSL 主要特性&#xff1a; 自监督前沿算法实现 PASSL 实现了…

自动驾驶传感器:惯性导航IMU原理

自动驾驶传感器&#xff1a;惯性导航IMU原理 附赠自动驾驶学习资料和量产经验&#xff1a;链接 组合导航里包含了GNSS卫星导航模块与IMU惯性导航模块&#xff0c;前一篇文章写了GNSS模块&#xff0c;本章写IMU惯导&#xff0c;也是本系列最后一篇文章。 1. 惯性测量单元&…

python django实战开发序列化器的一个应用心得分享

需求: 查询的时候返回不包括SharePasswd 字段, 但是新增操作需要用到该字段 再不写多个model模型和序列化器的前提下实现 如果您在查询&#xff08;GET 请求&#xff09;时不希望返回 SharePasswd 字段&#xff0c;但在新增&#xff08;POST 请求&#xff09;时需要用到该字段…

数据结构 - 用队列实现栈/用栈实现队列

用栈实现队列 思路&#xff1a; 队列是遵循队头出数据&#xff0c;队列进数据。 创建两个栈&#xff0c;一个左栈&#xff0c;一个右栈。左栈用来插入新数据&#xff0c;右栈用来出数据 我们要借用栈的性质也实现一个出数据&#xff0c;和入数据的功能&#xff0c;该怎么样实…

[flask]异常抛出和捕获异常

Python学习之Flask全局异常处理流程_flask 异常处理-CSDN博客 读取文件错误 OSError: [Errno 22] Invalid argument:_[errno 22] invalid argument: ..\\data\\snli_1.0\\-CSDN博客 异常触发 assert触发异常&#xff1a; 在Python中&#xff0c;使用assert语句可以检查某个条…

“智慧食堂”设计与实现|Springboot+ Mysql+Vue+Java+ B/S结构(可运行源码+数据库+设计文档)

本项目包含可运行源码数据库LW&#xff0c;文末可获取本项目的所有资料。 推荐阅读100套最新项目持续更新中..... 2024年计算机毕业论文&#xff08;设计&#xff09;学生选题参考合集推荐收藏&#xff08;包含Springboot、jsp、ssmvue等技术项目合集&#xff09; 目录 1. 功…

Unity urp渲染管线下,动态修改材质球surfaceType

在项目中遇到了需要代码动态修改材质球的surfaceType&#xff0c;使其动态切换是否透明的需求。 urp渲染管线下&#xff0c;动态修改材质球的surfaceType&#xff0c;查了大部分帖子&#xff0c;都有一些瑕疵&#xff0c;可能会造成透明后阴影投射有问题。 其次在webgl平台上…
最新文章