在 Wed 中应用 MyBatis(同时使用MVC架构模式,以及ThreadLocal 事务控制)
1. 在 Wed 中应用 MyBatis(同时使用MVC架构模式,以及ThreadLocal 事务控制)
文章目录
- 1. 在 Wed 中应用 MyBatis(同时使用MVC架构模式,以及ThreadLocal 事务控制)
- 2. 实现步骤:
- 1. 第一步:环境搭建
- 2. 第二步:前端页面 index.html
- 3. 第三步:创建pojo包、service包、dao包、web包、utils包,exceptions包
- 4. 第四步:编写 utils 包下的,获取 MyBatis,SqlSesion 连接的工具类
- 5. 第五步:定义pojo类:Account
- 6. 第六步:编写AccountDao接口,以及AccountDaoImpl实现类
- 7. 第七步:AccountDaoImpl 中编写了mybatis 代码,需要编写SQL映射文件了
- 8. 第八步:编写AccountService接口以及AccountServiceImpl
- 9. 第九步:编写 自定义 Exception 异常
- 10. 第十步:编写AccountController
- 11. 第十一步:运行测试:
- 2.1 补充说明:事务上的处理
- 3. MyBatis核心对象的作用域
- 3.1 SqlSessionFactoryBuilder
- 3.2 SqlSessionFactory
- 3.3 SqlSession
- 4. 总结:
- 5. 最后:
在 Web 中应用 MyBatis ,同时使用 MVC 架构模式,以及对应的 ThreadLocal 事务控制。
实现功能,银行账户的转账功能,同时进行事务上的处理。
需求描述:
实际简单的转账操作:

数据库表的设计和准备数据:


2. 实现步骤:
这里说明一下,开发可以
- 从后往前
- 也可以,从前往后
二者没有太大区别,你认为哪个方向更好编写,便按照哪个方向即可,我个人比较习惯从前往后,所以这里我就从前往后了。
1. 第一步:环境搭建
IDEA中创建Maven WEB应用
注意:这里的 Archetype : 选择org.apache.maven.archetypes:maven-archetype-webapp 不要选错了。

IDEA配置Tomcat,这里Tomcat使用10+版本。并部署应用到tomcat。






默认创建的maven web应用没有 java和 resources目录。

一般会自动添加上,如果没有的话,有两种手动添加上的方式:
- 第一种就是:直接在 IDEA 当的 main 目录下,新建

- 第二种修改:修改maven-archetype-webapp-1.4.jar中的配置文件



这里自动生成的:web.xml 文件的版本较低,内容有点不太合适,我们可以从 tomcat10 的样例文件中复制,然后修改

如下是:tomcat 10 当中的样例:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaeehttps://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"version="5.0"metadata-complete="true"></web-app>
-
删除
index.jsp文件,因为我们这个项目不使用JSP。只使用 html。 -
确定
pom.xml文件中的打包方式是war包。 -
引入相关依赖
-
- 编译器版本修改为 17
- 引入的依赖包括:mybatis,mysql驱动,junit,logback,servlet。

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.rainbowsea</groupId><artifactId>mybatis-004-web</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><name>mybatis-004-web Maven Webapp</name><!-- FIXME change it to the project's website --><url>http://www.example.com</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.7</maven.compiler.source><maven.compiler.target>1.7</maven.compiler.target></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><!-- mybatis 依赖--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.10</version></dependency><!-- mysql驱动依赖--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.30</version></dependency><!-- logback依赖--><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.11</version></dependency><!--servlet依赖--><dependency><groupId>jakarta.servlet</groupId><artifactId>jakarta.servlet-api</artifactId><version>5.0.0</version><scope>provided</scope></dependency></dependencies><build><finalName>mybatis-004-web</finalName><pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --><plugins><plugin><artifactId>maven-clean-plugin</artifactId><version>3.1.0</version></plugin><!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging --><plugin><artifactId>maven-resources-plugin</artifactId><version>3.0.2</version></plugin><plugin><artifactId>maven-compiler-plugin</artifactId><version>3.8.0</version></plugin><plugin><artifactId>maven-surefire-plugin</artifactId><version>2.22.1</version></plugin><plugin><artifactId>maven-war-plugin</artifactId><version>3.2.2</version></plugin><plugin><artifactId>maven-install-plugin</artifactId><version>2.5.2</version></plugin><plugin><artifactId>maven-deploy-plugin</artifactId><version>2.8.2</version></plugin></plugins></pluginManagement></build>
</project>
-
引入相关配置文件,放到resources目录下(全部放到类的根路径下)
-
- mybatis-config.xml
- AccountMapper.xml
- logback.xml
- jdbc.properties
-

-
logback.xml logbak 日志框架信息
-

-
<?xml version="1.0" encoding="UTF-8"?><configuration debug="false"><!-- 控制台输出 --><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern></encoder></appender><!--mybatis log configure--><logger name="com.apache.ibatis" level="TRACE"/><logger name="java.sql.Connection" level="DEBUG"/><logger name="java.sql.Statement" level="DEBUG"/><logger name="java.sql.PreparedStatement" level="DEBUG"/><!-- 日志输出级别,logback日志级别包括五个:TRACE < DEBUG < INFO < WARN < ERROR --><root level="DEBUG"><appender-ref ref="STDOUT"/><appender-ref ref="FILE"/></root></configuration> -
AccountMapper.xml SQl语句的映射文件
-
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--namespace先随意写一个--> <mapper namespace="account"><select id="selectByActno" resultType="com.rianbowsea.bank.pojo.Account">select * from t_act where actno = #{actno}</select> <!--#{pojo的属性名}--><update id="updateByActno">update t_act set balance = #{balance} where actno = #{actno}</update></mapper> -
jdb.properties 数据库连接信息的配置文件
-
jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mybatis jdbc.username=root jdbc.password=MySQL123 -
mybatis-config.xml MyBatis 的核心配置文件
-
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration><!--resource , 一定是从类路径下开始查找资源--><properties resource="jdbc.properties"></properties><environments default="mybatis"><environment id="mybatis"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><mappers><mapper resource="AccountMapper.xml"/></mappers> </configuration>
2. 第二步:前端页面 index.html
在Tomcat当中 ,index.html 默认就是开始页面,主页的。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>银行账户转账</title>
</head>
<body>
<form action="/bank/transfer" method="post">转出账户:<input type="text" name="fromActno"> <br>转入账户:<input type="text" name="toActno"> <br>转账金额:<input type="text" name="money"> <br><input type="submit" value="转账"></form>
</body>
</html>
3. 第三步:创建pojo包、service包、dao包、web包、utils包,exceptions包

4. 第四步:编写 utils 包下的,获取 MyBatis,SqlSesion 连接的工具类

package com.rianbowsea.bank.utils;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;public class SqlSessionUtil {// 工具类的构造方法一般都是私有话化的// 工具类中所有的方法都是静态的,直接类名即可调用,不需要 new 对象// 为了防止new对象,构造方法私有化。private SqlSessionUtil() {}private static SqlSessionFactory sessionFactory = null;// 静态代码块,类加载时执行// SqlSessionUtil 工具类在进行第一次加载的时候,解析mybatis-config.xml 文件,创建SqlSessionFactory对象。static {// 获取到 SqlSessionFactoryBuilder 对象SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();// 获取到SqlSessionFactory 对象// SQlsessionFactory对象,一个SqlSessionFactory对应一个 environment, 一个environment通常是一个数据库try {sessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));} catch (IOException e) {throw new RuntimeException(e);}}// 全局的,服务器级别的,一个服务器当中定义一个即可private static ThreadLocal<SqlSession> local = new ThreadLocal<>();/*** 获取会话对象** @return SqlSession*/public static SqlSession openSession() {// 先从 ThreadLocal 当中获取,获取到 SqlSession 对象SqlSession sqlSession = local.get();if (null == sqlSession) {// ThreadLocat 没有就, 创建一个sqlSession = sessionFactory.openSession();// 同时将其设置到 ThreadLocal容器当中,将SqlSession对象绑定到当前线程上local.set(sqlSession);}return sqlSession;}/*** 关闭SqlSession 对象(从当前线程中移除SqlSession 对象)* @param sqlSession*/public static void close(SqlSession sqlSession) {if(sqlSession != null) {// 1.先将其关闭sqlSession.close();// 2. 再将其当前线程移除ThreadLocal 当前线程外面,防止被其他线程拿到整个没用的线程local.remove();/*注意:移除SqlSession 对象和当前线程的绑定关系因为Tomcat 服务器是支持线程池的,也就是说,用过的先吃对象t1,可能下一I此还会使用整个t1(已经关闭,没用的)线程。*/}}
}
5. 第五步:定义pojo类:Account
对于 pojo 当中的类,一定要有 set 和 get 方法,以及无参数构造方法,不然,大部分的框架是无法通过反射机制,进行操作的,从而出现错误的。

package com.rianbowsea.bank.pojo;/*** 账户类,封装账户数据*/
public class Account {private Long id;private String actno;private Double balance;public Account() {}public Account(Long id, String actno, Double balance) {this.id = id;this.actno = actno;this.balance = balance;}@Overridepublic String toString() {return "Account{" +"id=" + id +", actno='" + actno + '\'' +", balance=" + balance +'}';}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getActno() {return actno;}public void setActno(String actno) {this.actno = actno;}public Double getBalance() {return balance;}public void setBalance(Double balance) {this.balance = balance;}
}
6. 第六步:编写AccountDao接口,以及AccountDaoImpl实现类
分析dao中至少要提供几个方法,才能完成转账:
- 转账前需要查询余额是否充足:selectByActno
- 转账时要更新账户:update
AccountDao

package com.rianbowsea.bank.dao;import com.rianbowsea.bank.pojo.Account;/*** 账户的DAO对象,负责t_act 表中数据的CRUD,一般一个表对应一个 DAO* 强调以下,DAO对象中的任何一个方法和业务不挂钩,没有任何业务逻辑在里头* DAo中的方法就是CRUD的,所以方法名大部分是:insertXxx,deletexxx,updatexxx,selectxxx*/
public interface AccountDao {/*** 根据账号查询账户信息* @param actno 账号* @return 账户信息*/Account selectActno(String actno);/*** 更新账户信息* @param account 被更新的账户信息* @return 1表示更新成功,其他表示更新失败*/int updateByActno(Account account);}
AccountDaoImpl

package com.rianbowsea.bank.dao.impl;import com.rianbowsea.bank.dao.AccountDao;
import com.rianbowsea.bank.pojo.Account;
import com.rianbowsea.bank.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;public class AccountDaoImpl implements AccountDao {private SqlSession sqlSession = SqlSessionUtil.openSession();@Overridepublic Account selectActno(String actno) {Account account = (Account) sqlSession.selectOne("account.selectByActno", actno);// 注意:事务的控制,都是放在业务层的,不是放在持久层DAo,更不放在utils工具层//sqlSession.close();return account;}@Overridepublic int updateByActno(Account account) {int count = sqlSession.update("account.updateByActno", account);// 注意:事务的控制,都是放在业务层的,不是放在持久层DAo,更不放在utils工具层//sqlSession.commit(); // 提交数据//sqlSession.close();return count;}
}
7. 第七步:AccountDaoImpl 中编写了mybatis 代码,需要编写SQL映射文件了
AccountMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace先随意写一个-->
<mapper namespace="account"><select id="selectByActno" resultType="com.rianbowsea.bank.pojo.Account">select * from t_act where actno = #{actno}</select>
<!--#{pojo的属性名}--><update id="updateByActno">update t_act set balance = #{balance} where actno = #{actno}</update></mapper>
8. 第八步:编写AccountService接口以及AccountServiceImpl
AccountService

package com.rianbowsea.bank.service;import com.rianbowsea.bank.exceptions.MoneyNotEnoughException;
import com.rianbowsea.bank.exceptions.TransferException;/*** 注意: 业务类当中的业务方法的名字在起名字的时候,最好见名知意,能够体现出具体的业务是做什么的* 账户业务类*/
public interface AccountService {/*** 账户转账业务** @param fromActno 转出账户* @param toActno 转入账户* @param money 转账金额*/void transfer(String fromActno, String toActno, double money) throws MoneyNotEnoughException, TransferException;}
AccountServiceImpl

package com.rianbowsea.bank.service.impl;import com.rianbowsea.bank.dao.AccountDao;
import com.rianbowsea.bank.dao.impl.AccountDaoImpl;
import com.rianbowsea.bank.exceptions.MoneyNotEnoughException;
import com.rianbowsea.bank.exceptions.TransferException;
import com.rianbowsea.bank.pojo.Account;
import com.rianbowsea.bank.service.AccountService;
import com.rianbowsea.bank.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;public class AccountServiceImpl implements AccountService {private AccountDao accountDao = new AccountDaoImpl();@Overridepublic void transfer(String fromActno, String toActno, double money) throws MoneyNotEnoughException, TransferException {// 添加事务控制代码SqlSession sqlSession = SqlSessionUtil.openSession();// 1.判断转出账户的金额是否充足(select)Account fromAct = accountDao.selectActno(fromActno);if (fromAct.getBalance() < money) {// 2.如果转出账户余额不足,提示用户throw new MoneyNotEnoughException("对不起,余额不足");}// 3. 如果转出账户余额充足,更新转出账户的余额(update)// 先在内存当中修改Account toACt = accountDao.selectActno(toActno);toACt.setBalance(toACt.getBalance() + money);fromAct.setBalance(fromAct.getBalance() - money);// 4. 更新转入账户的余额(update)int count = accountDao.updateByActno(toACt);count += accountDao.updateByActno(fromAct);// 模拟异常//String s = null;//s.toString();if(count !=2) {throw new TransferException("转账异常,未知原因");}// 注意:事务的控制,都是放在业务层的,不是放在持久层DAo,更不放在utils工具层sqlSession.commit(); // 提交数据sqlSession.close();}}
9. 第九步:编写 自定义 Exception 异常
MoneyNotEnoughException

package com.rianbowsea.bank.exceptions;/*** 余额不足异常*/
public class MoneyNotEnoughException extends Exception{public MoneyNotEnoughException() {}public MoneyNotEnoughException(String message) {super(message);}
}
TransferException

package com.rianbowsea.bank.exceptions;/*** 转账异常*/
public class TransferException extends Exception{public TransferException() {}public TransferException(String message) {super(message);}
}
10. 第十步:编写AccountController
AccountController

package com.rianbowsea.bank.web;import com.rianbowsea.bank.exceptions.MoneyNotEnoughException;
import com.rianbowsea.bank.exceptions.TransferException;
import com.rianbowsea.bank.service.AccountService;
import com.rianbowsea.bank.service.impl.AccountServiceImpl;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.IOException;@WebServlet("/transfer")
public class AccountServlet extends HttpServlet {// 为了让整个对象在其他方法中可以用,声明为实例变量private AccountService accountService = new AccountServiceImpl();@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,IOException {// 获取表单数据String fromActno = request.getParameter("fromActno");String toActno = request.getParameter("toActno");double money = Double.parseDouble(request.getParameter("money"));// 转账业务try {// 调用service的转账方法完成转账,(调用业务层)accountService.transfer(fromActno,toActno,money);// 程序能够走到这里,表示转账一定成功了// 调用View完成展示结果response.sendRedirect(request.getContextPath()+"/success.html");} catch (MoneyNotEnoughException e) {response.sendRedirect(request.getContextPath()+"/error.html");throw new RuntimeException(e);} catch (TransferException e) {response.sendRedirect(request.getContextPath()+"/error2.html");throw new RuntimeException(e);} catch (NullPointerException e) {response.sendRedirect(request.getContextPath()+"/error2.html");throw new RuntimeException(e);}}
}
11. 第十一步:运行测试:
首先测试,没有模拟异常,看是否可以转账成功。

模拟异常,看事务上的处理,是否成功,是否能成功回滚,是否会丢失数据 。

2.1 补充说明:事务上的处理
在之前的转账业务中,更新了两个账户,我们需要保证它们的同时成功或同时失败,这个时候就需要使用事务机制,在 transfer 方法开始执行时开启事务,直到两个更新都成功之后 ,为了保证service和dao中使用的SqlSession对象是同一个,可以将SqlSession对象存放到ThreadLocal当中。

注意:移除SqlSession 对象和当前线程的绑定关系
因为Tomcat 服务器是支持线程池的,也就是说,用过的先吃对象t1,可能下一I此还会使用整个t1(已经关闭,没用的)线程。
注意:事务的控制,都是放在业务层的,不是放在持久层DAo,更不放在utils工具层 .

3. MyBatis核心对象的作用域

3.1 SqlSessionFactoryBuilder

这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。
3.2 SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
3.3 SqlSession

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。 下面的示例就是一个确保 SqlSession 关闭的标准模式:
try (SqlSession session = sqlSessionFactory.openSession()) {// 你的应用逻辑代码
}
4. 总结:
- 为了保证 service 和 dao 中使用的SqlSession对象是同一个,可以将SqlSession对象存放到ThreadLocal当中。
- 注意:移除SqlSession 对象和当前线程的绑定关系
因为Tomcat 服务器是支持线程池的,也就是说,用过的先吃对象t1,可能下一I此还会使用整个t1(已经关闭,没用的)线程。
注意:事务的控制,都是放在业务层的,不是放在持久层DAo,更不放在utils工具层 .
SqlSessionFactoryBuilder: 这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。
SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
SqlSession 它的最佳的作用域是请求或方法作用域**。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 **也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。
5. 最后:
“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”
相关文章:
在 Wed 中应用 MyBatis(同时使用MVC架构模式,以及ThreadLocal 事务控制)
1. 在 Wed 中应用 MyBatis(同时使用MVC架构模式,以及ThreadLocal 事务控制) 文章目录 1. 在 Wed 中应用 MyBatis(同时使用MVC架构模式,以及ThreadLocal 事务控制)2. 实现步骤:1. 第一步…...
Elasticsearch index 设置 false,为什么还可以被检索到?
在 Elasticsearch 中,mapping 定义了索引中的字段类型及其处理方式。 近期有球友提问,为什么设置了 index: false 的字段仍能被检索。 本文将详细探讨这个问题,并引入列式存储的概念,帮助大家更好地理解 Elasticsearch 的存储和查…...
169. 多数元素
题目 给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 示例 1: 输入:nums [3,2,3]输出:3 …...
ADS基础教程19 - 电磁仿真(EM)基本概念和实操
EM介绍 一、引言二、基本概念1.EM介绍2.Momentum介绍3.FEM介绍4.Substrate介绍 三、创建Layout并进行Momentum仿真1.创建Layout2.添加Microtrip(微带线)3.添加Substrate4.Momentum仿真 四、总结 一、引言 本章节开始介绍EM的基本概念、内容以及实现具体…...
LabVIEW RT环境中因字符串拼接导致的系统崩溃问题
在LabVIEW实时操作系统(RT)环境中运行的应用程序出现字符串拼接后死机的问题,通常涉及内存管理、内存泄漏或其他资源管理问题。以下是一些指导和步骤,帮助解决这个问题: 1. 内存泄漏检测 字符串拼接会在内存中创建新…...
深层网络:层数多真的更好吗?
深层网络:层数多真的更好吗? 在深度学习的世界里,"深度"始终是一个热门话题。随着技术的发展,我们有了越来越多的方法来构建更深的神经网络,这似乎暗示着“层数越多,效果越好”。然而࿰…...
【QT5】<知识点> QT常用知识(更新中)
目录 一、更改文本颜色和格式 二、QT容器类 三、字符串与整数、浮点数之间的转换 四、QString常用功能 五、SpinBox的属性介绍 六、滑动、滚动、进度条和表盘LCD 七、时间、日期、定时器 一、更改文本颜色和格式 动态设置字体粗体:QFont对象的setBold方法动态…...
如何将AndroidStudio和IDEA的包名改为分层级目录
新版UIAndroidStudio 1、点击项目目录右上角如图所示的三个点点。 2、然后依次取消Hide empty middle package ,Flatten package的勾选 3、注意:一定要先取消hide的勾选,不然目录不会完全分级(做错了可以反过来重新设置&#x…...
北交字节联合提出ClassDiffusion: 使用显式类别引导的一致性个性化生成。
在个性化生成领域, 微调可能会引起过拟合导致模型无法生成与提示词一致的结果。针对这个问题,北交&字节联合提出ClassDiffusion,来提升个性化生成的一致性。 通过两个重要观察及理论分析提出了新的观点:一致性的损失是个性化概念语义偏移导致的, 还…...
37、matlab矩阵运算
1、前言 矩阵运算是指对矩阵的各种操作和运算,包括矩阵加法、矩阵减法、矩阵乘法、矩阵转置、求逆矩阵等。以下是常见的矩阵运算: 矩阵加法:对应位置的元素相加,要求加数和被加数的维度相同。 A B | a11 b11 | | a12 b12 | | …...
用软件实现的硬件——虚拟机
通过软件实现CPU和内存等硬件所具有的功能,并在计算机中运行循环的计算机技术称为虚拟机。使用虚拟机,就可以在一台计算机中运行多个循环出来的计算机。 近几年的计算机,除了硬件具有较高的性能外,CPU的性能也有了提升。因此&…...
[Shell编程学习路线]--shell中重定向和管道符(详细介绍)
🏡作者主页:点击! 🛠️Shell编程专栏:点击! ⏰️创作时间:2024年6月12日10点50分 🀄️文章质量:93分 ——前言—— 在Shell编程中,重定向和管道符是两个…...
Linux命令详解(1)
在Linux操作系统中,命令行界面(CLI)是一个强大的工具,它允许用户通过键入命令来与系统交互。无论是系统管理员还是普通用户,掌握一些基本的Linux命令都是非常重要的。在本文中,我们将探讨一些常用的Linux命…...
网工内推 | 深信服、中软国际技术支持工程师,最高13k*13薪
01 深信服 🔷招聘岗位:远程技术支持工程师 🔷任职要求: 一、专业能力和行业经验: ①具备友商同岗位工作经验1.5年以上,具备良好的分析和判断能力,有独立问题处理思路,具备常见协…...
实现卡片的展开缩放动画
原理,外层包裹一个元素,子元素分别是展开和收起的元素,然后对展开的元素添加动画,动画内容是随时间变化,将卡片的transform:rotateX属性进行调整,因为改变的是子元素的旋转,父元素高…...
实验:贪心算法
实验二:贪心算法 【实验目的】 应用贪心算法求解活动安排问题。 【实验性质】 验证性实验。 【实验要求】 活动安排问题是可以用贪心算法有效求解的很好的例子。 问题:有n个活动的集合A{1,2,…,n},其中每个活动都要求使用同一资源&…...
Python学习笔记12 -- 有关布尔值的详细说明
一、布尔表达式 最终值为true 或者false 二、常见形式: 1、常量:true false 2、比较运算: and ! 3、复合运算: and and or 4、其他 例:检测闰年: def specialYearMine(year):if (year%4 …...
SQL-窗口函数合集
目录 1.窗口函数简介2.窗口的定义3.相关题目示例3.1 PERCENT_RANK()2346 以百分比计算排名 3.2 FIRST_VALUE()/LAST_VALUE()/NTH_VALUE()2388 将表中的空值更改为前一个值 1.窗口函数简介 MySQL 开窗函数(Window Functions)是 MySQL 8.0 版本引入的一个…...
2024 全球软件研发技术大会官宣,50+专家共话软件智能新范式!
2024年的全球软件研发技术大会(SDCon)由CSDN和高端IT咨询与教育平台Boolan联合主办,将于7月4日至5日在北京威斯汀酒店举行。本次大会的主题为“大模型驱动软件智能化新范式”,旨在探讨大模型和开源技术的发展如何引领全球软件研发…...
opencv快速安装以及各种查看版本命令
安装opencv并查看其版本,直接通过一个可执行文件实现。 #!/bin/bashwget https://codeload.github.com/opencv/opencv/zip/3.4 -O opencv-3.4.zip && unzip opencv-3.4.zip && cd opencv-3.4 && \mkdir build && cd build &&a…...
手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
汽车生产虚拟实训中的技能提升与生产优化
在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...
均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...
深入浅出Diffusion模型:从原理到实践的全方位教程
I. 引言:生成式AI的黎明 – Diffusion模型是什么? 近年来,生成式人工智能(Generative AI)领域取得了爆炸性的进展,模型能够根据简单的文本提示创作出逼真的图像、连贯的文本,乃至更多令人惊叹的…...
消防一体化安全管控平台:构建消防“一张图”和APP统一管理
在城市的某个角落,一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延,滚滚浓烟弥漫开来,周围群众的生命财产安全受到严重威胁。就在这千钧一发之际,消防救援队伍迅速行动,而豪越科技消防一体化安全管控平台构建的消防“…...


