👋 大家好,我是 阿问学长!专注于分享优质开源项目解析、毕业设计项目指导支持、幼小初高教辅资料推荐等,欢迎关注交流!🚀

06-Spring数据访问与JDBC模板

📖 本文概述

本文是SSM框架系列Spring进阶篇的第三篇,将深入探讨Spring的数据访问技术,重点介绍JdbcTemplate的使用和最佳实践。通过详细的代码示例,帮助读者掌握Spring数据访问层的设计和实现。

🎯 学习目标

  • 深入理解Spring数据访问架构
  • 掌握JdbcTemplate的各种用法
  • 学会处理数据访问异常
  • 了解数据源配置和连接池管理
  • 掌握数据访问层的最佳实践

1. Spring数据访问架构

1.1 数据访问层架构

/*** Spring数据访问层架构演示*/
public class DataAccessArchitecture {/*** Spring数据访问层的核心组件:* * 1. DataSource - 数据源,管理数据库连接* 2. JdbcTemplate - JDBC模板,简化JDBC操作* 3. NamedParameterJdbcTemplate - 命名参数JDBC模板* 4. SimpleJdbcInsert - 简化插入操作* 5. SimpleJdbcCall - 简化存储过程调用* 6. DataAccessException - 数据访问异常体系*//*** 数据访问层的层次结构:* * Service Layer (业务层)*     ↓* DAO Layer (数据访问层)*     ↓* JdbcTemplate (JDBC模板)*     ↓* DataSource (数据源)*     ↓* Database (数据库)*//*** Spring数据访问的优势:* * 1. 统一的异常体系* 2. 资源管理自动化* 3. 事务管理集成* 4. 模板方法模式简化代码* 5. 支持多种数据访问技术*/
}

1.2 数据源配置

/*** 数据源配置示例*/
@Configuration
public class DataSourceConfig {/*** HikariCP数据源配置(推荐)*/@Bean@Primarypublic DataSource hikariDataSource() {HikariConfig config = new HikariConfig();// 基本连接信息config.setJdbcUrl("jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC");config.setUsername("root");config.setPassword("password");config.setDriverClassName("com.mysql.cj.jdbc.Driver");// 连接池配置config.setMaximumPoolSize(20);              // 最大连接数config.setMinimumIdle(5);                   // 最小空闲连接数config.setConnectionTimeout(30000);         // 连接超时时间(毫秒)config.setIdleTimeout(600000);              // 空闲超时时间(毫秒)config.setMaxLifetime(1800000);             // 连接最大生存时间(毫秒)config.setLeakDetectionThreshold(60000);    // 连接泄漏检测阈值// 连接测试config.setConnectionTestQuery("SELECT 1");// 连接池名称config.setPoolName("HikariCP-Pool");return new HikariDataSource(config);}/*** Druid数据源配置*/@Beanpublic DataSource druidDataSource() {DruidDataSource dataSource = new DruidDataSource();// 基本连接信息dataSource.setUrl("jdbc:mysql://localhost:3306/testdb");dataSource.setUsername("root");dataSource.setPassword("password");dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");// 连接池配置dataSource.setInitialSize(5);               // 初始连接数dataSource.setMinIdle(5);                   // 最小空闲连接数dataSource.setMaxActive(20);                // 最大连接数dataSource.setMaxWait(60000);               // 获取连接最大等待时间// 连接有效性检测dataSource.setTestWhileIdle(true);dataSource.setTestOnBorrow(false);dataSource.setTestOnReturn(false);dataSource.setValidationQuery("SELECT 1");dataSource.setValidationQueryTimeout(30);// 连接回收dataSource.setTimeBetweenEvictionRunsMillis(60000);dataSource.setMinEvictableIdleTimeMillis(300000);// 监控配置dataSource.setFilters("stat,wall,log4j2");return dataSource;}/*** 嵌入式数据源(用于测试)*/@Bean@Profile("test")public DataSource embeddedDataSource() {return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).addScript("classpath:schema.sql").addScript("classpath:data.sql").build();}/*** JNDI数据源*/@Bean@Profile("production")public DataSource jndiDataSource() {JndiDataSourceLookup lookup = new JndiDataSourceLookup();return lookup.getDataSource("java:comp/env/jdbc/MyDataSource");}
}

2. JdbcTemplate基础用法

2.1 基本CRUD操作

/*** JdbcTemplate基本CRUD操作*/
@Repository
public class UserDaoImpl implements UserDao {@Autowiredprivate JdbcTemplate jdbcTemplate;/*** 插入操作*/@Overridepublic int save(User user) {String sql = "INSERT INTO users (username, email, age, create_time) VALUES (?, ?, ?, ?)";return jdbcTemplate.update(sql, user.getUsername(), user.getEmail(), user.getAge(), new Timestamp(System.currentTimeMillis()));}/*** 插入并返回自增主键*/@Overridepublic User saveAndReturnKey(User user) {String sql = "INSERT INTO users (username, email, age, create_time) VALUES (?, ?, ?, ?)";KeyHolder keyHolder = new GeneratedKeyHolder();jdbcTemplate.update(connection -> {PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);ps.setString(1, user.getUsername());ps.setString(2, user.getEmail());ps.setInt(3, user.getAge());ps.setTimestamp(4, new Timestamp(System.currentTimeMillis()));return ps;}, keyHolder);user.setId(keyHolder.getKey().longValue());return user;}/*** 更新操作*/@Overridepublic int update(User user) {String sql = "UPDATE users SET username = ?, email = ?, age = ?, update_time = ? WHERE id = ?";return jdbcTemplate.update(sql,user.getUsername(),user.getEmail(),user.getAge(),new Timestamp(System.currentTimeMillis()),user.getId());}/*** 删除操作*/@Overridepublic int deleteById(Long id) {String sql = "DELETE FROM users WHERE id = ?";return jdbcTemplate.update(sql, id);}/*** 批量删除*/@Overridepublic int[] deleteByIds(List<Long> ids) {String sql = "DELETE FROM users WHERE id = ?";List<Object[]> batchArgs = ids.stream().map(id -> new Object[]{id}).collect(Collectors.toList());return jdbcTemplate.batchUpdate(sql, batchArgs);}/*** 查询单个对象*/@Overridepublic User findById(Long id) {String sql = "SELECT id, username, email, age, create_time, update_time FROM users WHERE id = ?";try {return jdbcTemplate.queryForObject(sql, new UserRowMapper(), id);} catch (EmptyResultDataAccessException e) {return null; // 没有找到记录}}/*** 查询列表*/@Overridepublic List<User> findAll() {String sql = "SELECT id, username, email, age, create_time, update_time FROM users ORDER BY id";return jdbcTemplate.query(sql, new UserRowMapper());}/*** 条件查询*/@Overridepublic List<User> findByAge(int minAge, int maxAge) {String sql = "SELECT id, username, email, age, create_time, update_time FROM users WHERE age BETWEEN ? AND ?";return jdbcTemplate.query(sql, new UserRowMapper(), minAge, maxAge);}/*** 统计查询*/@Overridepublic long count() {String sql = "SELECT COUNT(*) FROM users";return jdbcTemplate.queryForObject(sql, Long.class);}/*** 检查存在性*/@Overridepublic boolean existsById(Long id) {String sql = "SELECT COUNT(*) FROM users WHERE id = ?";Integer count = jdbcTemplate.queryForObject(sql, Integer.class, id);return count != null && count > 0;}
}

2.2 RowMapper实现

/*** 用户行映射器*/
public class UserRowMapper implements RowMapper<User> {@Overridepublic User mapRow(ResultSet rs, int rowNum) throws SQLException {User user = new User();user.setId(rs.getLong("id"));user.setUsername(rs.getString("username"));user.setEmail(rs.getString("email"));user.setAge(rs.getInt("age"));user.setCreateTime(rs.getTimestamp("create_time"));user.setUpdateTime(rs.getTimestamp("update_time"));return user;}
}/*** 使用Lambda表达式的RowMapper*/
@Repository
public class LambdaUserDao {@Autowiredprivate JdbcTemplate jdbcTemplate;/*** 使用Lambda表达式简化RowMapper*/public List<User> findAllWithLambda() {String sql = "SELECT id, username, email, age, create_time, update_time FROM users";return jdbcTemplate.query(sql, (rs, rowNum) -> {User user = new User();user.setId(rs.getLong("id"));user.setUsername(rs.getString("username"));user.setEmail(rs.getString("email"));user.setAge(rs.getInt("age"));user.setCreateTime(rs.getTimestamp("create_time"));user.setUpdateTime(rs.getTimestamp("update_time"));return user;});}/*** 使用BeanPropertyRowMapper*/public List<User> findAllWithBeanMapper() {String sql = "SELECT id, username, email, age, create_time as createTime, update_time as updateTime FROM users";return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(User.class));}
}

3. NamedParameterJdbcTemplate

3.1 命名参数的使用

/*** NamedParameterJdbcTemplate使用示例*/
@Repository
public class NamedParameterUserDao {@Autowiredprivate NamedParameterJdbcTemplate namedParameterJdbcTemplate;/*** 使用Map传递参数*/public User findByUsernameAndEmail(String username, String email) {String sql = "SELECT * FROM users WHERE username = :username AND email = :email";Map<String, Object> params = new HashMap<>();params.put("username", username);params.put("email", email);try {return namedParameterJdbcTemplate.queryForObject(sql, params, new UserRowMapper());} catch (EmptyResultDataAccessException e) {return null;}}/*** 使用SqlParameterSource*/public int saveWithParameterSource(User user) {String sql = "INSERT INTO users (username, email, age, create_time) " +"VALUES (:username, :email, :age, :createTime)";SqlParameterSource params = new BeanPropertySqlParameterSource(user);return namedParameterJdbcTemplate.update(sql, params);}/*** 使用MapSqlParameterSource*/public List<User> findByAgeRange(int minAge, int maxAge) {String sql = "SELECT * FROM users WHERE age BETWEEN :minAge AND :maxAge ORDER BY age";MapSqlParameterSource params = new MapSqlParameterSource();params.addValue("minAge", minAge);params.addValue("maxAge", maxAge);return namedParameterJdbcTemplate.query(sql, params, new UserRowMapper());}/*** IN查询*/public List<User> findByIds(List<Long> ids) {String sql = "SELECT * FROM users WHERE id IN (:ids)";Map<String, Object> params = Collections.singletonMap("ids", ids);return namedParameterJdbcTemplate.query(sql, params, new UserRowMapper());}/*** 批量操作*/public int[] batchSave(List<User> users) {String sql = "INSERT INTO users (username, email, age, create_time) " +"VALUES (:username, :email, :age, :createTime)";SqlParameterSource[] batchParams = users.stream().map(BeanPropertySqlParameterSource::new).toArray(SqlParameterSource[]::new);return namedParameterJdbcTemplate.batchUpdate(sql, batchParams);}/*** 复杂查询条件*/public List<User> findByComplexConditions(UserSearchCriteria criteria) {StringBuilder sql = new StringBuilder("SELECT * FROM users WHERE 1=1");MapSqlParameterSource params = new MapSqlParameterSource();if (criteria.getUsername() != null) {sql.append(" AND username LIKE :username");params.addValue("username", "%" + criteria.getUsername() + "%");}if (criteria.getEmail() != null) {sql.append(" AND email = :email");params.addValue("email", criteria.getEmail());}if (criteria.getMinAge() != null) {sql.append(" AND age >= :minAge");params.addValue("minAge", criteria.getMinAge());}if (criteria.getMaxAge() != null) {sql.append(" AND age <= :maxAge");params.addValue("maxAge", criteria.getMaxAge());}sql.append(" ORDER BY id");return namedParameterJdbcTemplate.query(sql.toString(), params, new UserRowMapper());}
}/*** 搜索条件类*/
public class UserSearchCriteria {private String username;private String email;private Integer minAge;private Integer maxAge;// getter/setter方法
}

4. SimpleJdbcInsert和SimpleJdbcCall

4.1 SimpleJdbcInsert使用

/*** SimpleJdbcInsert使用示例*/
@Repository
public class SimpleJdbcInsertUserDao {private SimpleJdbcInsert simpleJdbcInsert;@Autowiredpublic SimpleJdbcInsertUserDao(DataSource dataSource) {this.simpleJdbcInsert = new SimpleJdbcInsert(dataSource).withTableName("users").usingGeneratedKeyColumns("id");}/*** 简单插入操作*/public Long save(User user) {Map<String, Object> parameters = new HashMap<>();parameters.put("username", user.getUsername());parameters.put("email", user.getEmail());parameters.put("age", user.getAge());parameters.put("create_time", new Timestamp(System.currentTimeMillis()));Number key = simpleJdbcInsert.executeAndReturnKey(parameters);return key.longValue();}/*** 使用BeanPropertySqlParameterSource*/public Long saveWithBean(User user) {user.setCreateTime(new Timestamp(System.currentTimeMillis()));SqlParameterSource parameters = new BeanPropertySqlParameterSource(user);Number key = simpleJdbcInsert.executeAndReturnKey(parameters);return key.longValue();}/*** 批量插入*/public void batchSave(List<User> users) {Map<String, Object>[] batchValues = users.stream().map(user -> {Map<String, Object> params = new HashMap<>();params.put("username", user.getUsername());params.put("email", user.getEmail());params.put("age", user.getAge());params.put("create_time", new Timestamp(System.currentTimeMillis()));return params;}).toArray(Map[]::new);simpleJdbcInsert.executeBatch(batchValues);}
}

4.2 SimpleJdbcCall使用

/*** SimpleJdbcCall使用示例*/
@Repository
public class SimpleJdbcCallUserDao {private SimpleJdbcCall getUserByIdCall;private SimpleJdbcCall updateUserAgeCall;@Autowiredpublic SimpleJdbcCallUserDao(DataSource dataSource) {JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);// 配置存储过程调用this.getUserByIdCall = new SimpleJdbcCall(jdbcTemplate).withProcedureName("get_user_by_id");this.updateUserAgeCall = new SimpleJdbcCall(jdbcTemplate).withProcedureName("update_user_age").declareParameters(new SqlParameter("user_id", Types.BIGINT),new SqlParameter("new_age", Types.INTEGER),new SqlOutParameter("result", Types.INTEGER));}/*** 调用存储过程查询用户*/public User getUserById(Long id) {SqlParameterSource in = new MapSqlParameterSource().addValue("user_id", id);Map<String, Object> result = getUserByIdCall.execute(in);// 处理结果集@SuppressWarnings("unchecked")List<Map<String, Object>> rows = (List<Map<String, Object>>) result.get("#result-set-1");if (rows.isEmpty()) {return null;}Map<String, Object> row = rows.get(0);User user = new User();user.setId(((Number) row.get("id")).longValue());user.setUsername((String) row.get("username"));user.setEmail((String) row.get("email"));user.setAge(((Number) row.get("age")).intValue());return user;}/*** 调用存储过程更新用户年龄*/public boolean updateUserAge(Long userId, int newAge) {SqlParameterSource in = new MapSqlParameterSource().addValue("user_id", userId).addValue("new_age", newAge);Map<String, Object> result = updateUserAgeCall.execute(in);Integer returnValue = (Integer) result.get("result");return returnValue != null && returnValue > 0;}/*** 调用函数*/public String getUsernameById(Long id) {SimpleJdbcCall function = new SimpleJdbcCall(new JdbcTemplate(dataSource)).withFunctionName("get_username_by_id").declareParameters(new SqlParameter("user_id", Types.BIGINT),new SqlReturnResultSet("result", new UserRowMapper()));SqlParameterSource in = new MapSqlParameterSource().addValue("user_id", id);String username = function.executeFunction(String.class, in);return username;}
}

5. 异常处理

5.1 数据访问异常体系

/*** Spring数据访问异常处理*/
@Repository
public class ExceptionHandlingUserDao {@Autowiredprivate JdbcTemplate jdbcTemplate;private static final Logger logger = LoggerFactory.getLogger(ExceptionHandlingUserDao.class);/*** 处理各种数据访问异常*/public User saveUser(User user) {String sql = "INSERT INTO users (username, email, age) VALUES (?, ?, ?)";try {KeyHolder keyHolder = new GeneratedKeyHolder();jdbcTemplate.update(connection -> {PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);ps.setString(1, user.getUsername());ps.setString(2, user.getEmail());ps.setInt(3, user.getAge());return ps;}, keyHolder);user.setId(keyHolder.getKey().longValue());return user;} catch (DuplicateKeyException e) {logger.error("用户名或邮箱已存在: {}", user.getUsername(), e);throw new UserAlreadyExistsException("用户名或邮箱已存在", e);} catch (DataIntegrityViolationException e) {logger.error("数据完整性约束违反: {}", user.getUsername(), e);throw new InvalidUserDataException("用户数据不符合约束条件", e);} catch (DataAccessException e) {logger.error("数据访问异常: {}", user.getUsername(), e);throw new UserDataAccessException("保存用户时发生数据库错误", e);}}/*** 处理查询异常*/public User findUserById(Long id) {String sql = "SELECT * FROM users WHERE id = ?";try {return jdbcTemplate.queryForObject(sql, new UserRowMapper(), id);} catch (EmptyResultDataAccessException e) {logger.debug("用户不存在: {}", id);return null;} catch (IncorrectResultSizeDataAccessException e) {logger.error("查询返回多个结果,期望单个结果: {}", id, e);throw new DataInconsistencyException("数据不一致,ID对应多个用户", e);} catch (DataAccessException e) {logger.error("查询用户时发生数据库错误: {}", id, e);throw new UserDataAccessException("查询用户时发生数据库错误", e);}}/*** 事务回滚异常处理*/@Transactionalpublic void transferUserData(Long fromUserId, Long toUserId) {try {// 模拟数据转移操作User fromUser = findUserById(fromUserId);User toUser = findUserById(toUserId);if (fromUser == null || toUser == null) {throw new UserNotFoundException("用户不存在");}// 执行转移逻辑performDataTransfer(fromUser, toUser);} catch (DataAccessException e) {logger.error("数据转移失败,事务将回滚", e);throw new DataTransferException("数据转移失败", e);}}private void performDataTransfer(User fromUser, User toUser) {// 模拟数据转移逻辑}
}/*** 自定义异常类*/
public class UserAlreadyExistsException extends RuntimeException {public UserAlreadyExistsException(String message, Throwable cause) {super(message, cause);}
}public class InvalidUserDataException extends RuntimeException {public InvalidUserDataException(String message, Throwable cause) {super(message, cause);}
}public class UserDataAccessException extends RuntimeException {public UserDataAccessException(String message, Throwable cause) {super(message, cause);}
}public class DataInconsistencyException extends RuntimeException {public DataInconsistencyException(String message, Throwable cause) {super(message, cause);}
}public class UserNotFoundException extends RuntimeException {public UserNotFoundException(String message) {super(message);}
}public class DataTransferException extends RuntimeException {public DataTransferException(String message, Throwable cause) {super(message, cause);}
}

6. 最佳实践

6.1 DAO层设计模式

/*** DAO层设计最佳实践*/
public interface BaseDao<T, ID> {T save(T entity);T update(T entity);void deleteById(ID id);T findById(ID id);List<T> findAll();long count();boolean existsById(ID id);
}/*** 抽象DAO基类*/
public abstract class AbstractJdbcDao<T, ID> implements BaseDao<T, ID> {@Autowiredprotected JdbcTemplate jdbcTemplate;@Autowiredprotected NamedParameterJdbcTemplate namedParameterJdbcTemplate;protected abstract String getTableName();protected abstract String getIdColumnName();protected abstract RowMapper<T> getRowMapper();protected abstract Map<String, Object> entityToMap(T entity);@Overridepublic T findById(ID id) {String sql = String.format("SELECT * FROM %s WHERE %s = ?", getTableName(), getIdColumnName());try {return jdbcTemplate.queryForObject(sql, getRowMapper(), id);} catch (EmptyResultDataAccessException e) {return null;}}@Overridepublic List<T> findAll() {String sql = String.format("SELECT * FROM %s ORDER BY %s", getTableName(), getIdColumnName());return jdbcTemplate.query(sql, getRowMapper());}@Overridepublic long count() {String sql = String.format("SELECT COUNT(*) FROM %s", getTableName());return jdbcTemplate.queryForObject(sql, Long.class);}@Overridepublic boolean existsById(ID id) {String sql = String.format("SELECT COUNT(*) FROM %s WHERE %s = ?", getTableName(), getIdColumnName());Integer count = jdbcTemplate.queryForObject(sql, Integer.class, id);return count != null && count > 0;}
}/*** 具体DAO实现*/
@Repository
public class UserDaoImpl extends AbstractJdbcDao<User, Long> implements UserDao {@Overrideprotected String getTableName() {return "users";}@Overrideprotected String getIdColumnName() {return "id";}@Overrideprotected RowMapper<User> getRowMapper() {return new UserRowMapper();}@Overrideprotected Map<String, Object> entityToMap(User user) {Map<String, Object> map = new HashMap<>();map.put("username", user.getUsername());map.put("email", user.getEmail());map.put("age", user.getAge());map.put("create_time", user.getCreateTime());map.put("update_time", user.getUpdateTime());return map;}@Overridepublic User save(User user) {if (user.getId() == null) {return insert(user);} else {update(user);return user;}}private User insert(User user) {String sql = "INSERT INTO users (username, email, age, create_time) VALUES (?, ?, ?, ?)";KeyHolder keyHolder = new GeneratedKeyHolder();jdbcTemplate.update(connection -> {PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);ps.setString(1, user.getUsername());ps.setString(2, user.getEmail());ps.setInt(3, user.getAge());ps.setTimestamp(4, new Timestamp(System.currentTimeMillis()));return ps;}, keyHolder);user.setId(keyHolder.getKey().longValue());return user;}@Overridepublic User update(User user) {String sql = "UPDATE users SET username = ?, email = ?, age = ?, update_time = ? WHERE id = ?";int rows = jdbcTemplate.update(sql,user.getUsername(),user.getEmail(),user.getAge(),new Timestamp(System.currentTimeMillis()),user.getId());if (rows == 0) {throw new UserNotFoundException("用户不存在: " + user.getId());}return user;}@Overridepublic void deleteById(Long id) {String sql = "DELETE FROM users WHERE id = ?";int rows = jdbcTemplate.update(sql, id);if (rows == 0) {throw new UserNotFoundException("用户不存在: " + id);}}/*** 自定义查询方法*/public List<User> findByUsername(String username) {String sql = "SELECT * FROM users WHERE username LIKE ?";return jdbcTemplate.query(sql, getRowMapper(), "%" + username + "%");}public List<User> findByAgeRange(int minAge, int maxAge) {String sql = "SELECT * FROM users WHERE age BETWEEN ? AND ? ORDER BY age";return jdbcTemplate.query(sql, getRowMapper(), minAge, maxAge);}
}

7. 小结

本文深入介绍了Spring的数据访问技术:

  1. 数据访问架构:Spring数据访问层的核心组件和架构
  2. JdbcTemplate:基本CRUD操作和RowMapper使用
  3. 命名参数模板:NamedParameterJdbcTemplate的各种用法
  4. 简化操作:SimpleJdbcInsert和SimpleJdbcCall的使用
  5. 异常处理:数据访问异常体系和处理策略
  6. 最佳实践:DAO层设计模式和代码组织

掌握Spring数据访问的关键点:

  • 正确配置数据源和连接池
  • 熟练使用JdbcTemplate进行数据操作
  • 合理处理数据访问异常
  • 设计清晰的DAO层架构
  • 选择合适的参数传递方式

🔗 下一篇预告

下一篇文章将介绍Spring Web开发基础,学习如何使用Spring进行Web应用开发。


相关文章:

  • 上一篇:Spring事务管理深入解析
  • [下一篇:Spring Web开发基础](./Spring Web开发基础.md)
  • 返回目录

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

下一代IT服务管理:ITIL5会是什么样?

ITIL4发布到现在也就5年多时间&#xff0c;按照以往的更新节奏&#xff0c;ITIL5最早也得2027年之后。但现在IT发展的速度&#xff0c;跟以前完全不是一个量级。AI都快把我们的饭碗抢了&#xff08;开个玩笑&#xff09;&#xff0c;ITIL要是还按部就班&#xff0c;估计真要被时…

最新研究进展:2023-2025年神经机器翻译突破性成果

文章目录 一、模型架构创新 1.1 混合架构的崛起 1.2 多模态翻译的突破 1.3 大语言模型与NMT的深度融合(2023-2024) 1.4 非自回归翻译(NAT)的效率革命(2024) 二、数据与训练策略优化 2.1 低资源语言翻译的飞跃 2.2 动态数据增强技术 三、效率与部署 3.1 模型压缩与加速 3.…

OpenTelemetry WebSocket 监控终极方案:打通最后一公里

概述 OpenTelemetry&#xff0c;以下简称 OTEL&#xff0c;是由 CNCF 托管的“一站式可观测性标准”&#xff0c;把指标、链路、日志三大信号统一为单一 SDK/API&#xff0c;零侵入地采集从浏览器、移动端到后端、容器、云服务的全栈遥测数据&#xff0c;并支持 40 后端一键导…

VS Code 出现的 Web 视图加载错误和服务工作者注册失败问题解决方案

针对 VS Code 或 Cursor &#xff08;vscode系&#xff09;中出现的 Web 视图加载错误和服务工作者注册失败问题&#xff0c;以下是永久性解决方案的完整操作指南&#xff1a;解决方案步骤打开命令面板 使用快捷键 CtrlShiftP&#xff08;Windows/Linux&#xff09;或 CmdShift…

【qml-4】qml与c++交互(类型多例)

背景&#xff1a; 【qml-1】qml与c交互第一次尝试&#xff08;实例注入&#xff09; 【qml-2】尝试一个有模式的qml弹窗 【qml-3】qml与c交互第二次尝试&#xff08;类型注册&#xff09; 【qml-4】qml与c交互&#xff08;类型多例&#xff09; 【qml-5】qml与c交互&#…

图数据库如何构筑 Web3 风控防线 聚焦批量注册与链上盗转 悦数图数据库

随着 Web3 生态的不断演进&#xff0c;链上风险呈现出团伙化、隐蔽化和动态化的趋势&#xff0c;传统的单点风控手段已难以应对复杂多变的攻击模式。尤其在批量注册薅羊毛与链上交易盗转洗钱等高频风险场景中&#xff0c;攻击者往往通过伪造身份、跨链操作、多层嵌套转账等方式…

恒流源电路学习

恒流源的设计原理&#xff1a; 如图所示你可以看到右边的的推到公式得到红点处的电压是一个和左边相关的定值&#xff0c;所以呢右边的电流就是电压除以那个4Ω&#xff0c;所以得到右边的电路的电流大体是一个定值&#xff0c;不管你再加什么东西都可以保持这个电流&#xff…

基于生成对抗网络的模糊图像恢复原理与技术实现

1. 引言图像模糊是数字图像处理中的常见问题&#xff0c;其成因包括相机抖动、物体运动、聚焦不良等。传统方法如维纳滤波、Lucy-Richardson 算法等依赖于模糊核估计和逆滤波&#xff0c;在复杂场景下性能有限。生成对抗网络&#xff08;Generative Adversarial Networks, GAN&…

【Doris 系列】Doris IP 变更修复

FE 恢复 异常日志 查看 fe.out 会有以下报错&#xff0c;此时 fe 进程是无法启动的&#xff0c;操作前注意备份所有 fe 的元数据并停止上游读写动作&#xff01; java.io.IOException: the self host 192.168.31.78 does not equal to the host in ROLE file 192.168.31.81. Yo…

安卓14系统应用收不到开机广播

安卓14系统应用收不到开机广播 - Wesley’s Blog 前段时间有测试反馈在安卓14 上面某系统应用恢复出厂设置后没有自启动&#xff0c;究竟是什么原因呢&#xff1f; 回顾 Android 从3.1开始&#xff0c;会将新安装并且从未被启动的应用置为“STOPPED”状态&#xff0c;或者被…

C# Attribute 方法扩展

场景 刚写完一个干净利落的方法&#xff0c;比如保存数据到数据库&#xff0c;逻辑清晰、结构优雅&#xff0c; 第二天&#xff0c;“嘿&#xff0c;保存完数据&#xff0c;记得给客户发个邮件哦~” 第三天&#xff0c;“能不能再发个消息通知其他系统&#xff1f;” 第四天&am…

【URP】[法线贴图]为什么主要是蓝色的?

【从UnityURP开始探索游戏渲染】专栏-直达 法线贴图呈现蓝紫色调&#xff08;尤其以蓝色为主&#xff09;是由其‌存储原理、切线空间坐标系设计及颜色编码规则共同决定的‌。 核心原因&#xff1a;法线向量的存储规则‌ ‌法线向量的物理范围‌ 法线是单位向量&#xff0c;…

驱动开发系列63 - NVIDIA 开源GPU驱动open-gpu-kernel-modules编译调试

目录 一:通过apt方式安装nvidia 驱动 二:通过 .run 方式安装nvidia驱动 三:编译安装nvidia开源内核驱动 四:验证和调试 五:卸载驱动 1. 以apt方式安装nvidia 驱动的卸载方法 2. 以.run方式安装nvidia驱动的卸载方法 六:安装CUDA环境 一:通过apt方式安装nvidia 驱动…

对KingbaseES架构的解析:从读写分离到异地灾备的技术实现与保障机制

声明&#xff1a;文章为本人真实测评博客&#xff0c;非广告&#xff0c;并没有推广该平台 &#xff0c;为用户体验文章 本人旨在分享最真实的用户体验&#xff0c;为关注此类产品的朋友们提供一个客观的参考。 文章目录一、架构全景&#xff1a;四级高可用构建数字基础1.1 物…

Visual Studio中的常用调试功能(上)

1、利用断点进行调试添加断点的方式有以下几种1.键盘快捷键F92.通过菜单【Debug&#xff08;调试&#xff09;】-》【Toggle BreakPoint&#xff08;切换断点&#xff09;】3.点击代码行左边的空白处&#xff08;推荐&#xff09;设置断点后&#xff0c;按F5运行程序&#xff0…

Linux -- 线程同步

1.1条件变量 (1)当⼀个线程互斥地访问某个变量时&#xff0c;它可能发现在其它线程改变状态之前&#xff0c;它什么也做不了。 (2)例如⼀个线程访问队列时&#xff0c;发现队列为空&#xff0c;它只能等待&#xff0c;只到其它线程将⼀个节点添加到队列 中。这种情况就需要⽤到…

前端进阶指南:JavaScript性能优化实战全解析

深入剖析 JavaScript 性能瓶颈&#xff0c;分享优化技巧与最佳实践&#xff0c;让你的前端应用更快、更稳、更流畅。 &#x1f4d1; 目录 一、前言 二、性能瓶颈的常见来源 三、JavaScript代码优化技巧 1. 避免重复计算 2. 合理使用防抖与节流 3. 使用事件委托 四、渲染…

RabbitMQ:SpringAMQP Direct Exchange(直连型交换机)

目录一、案例需求二、基础配置三、代码实现直连型交换机也叫做定向交换机&#xff0c;通过RoutingKey绑定交换机与队列直接的关系。 生产者源码 消费者源码 一、案例需求 在RabbitMQ控制台中&#xff0c;声明队列direct.queue1和direct.queue2。在RabbitMQ控制台中&#xff…

implement libtime on Windows

因为Windows的time命令和Linux的time命令不一样&#xff0c;尝试实现libtime libtime.h /** libtime.h - 跨平台时间测量库* 功能&#xff1a;执行外部命令并测量其运行时间和资源使用*/#ifndef LIBTIME_H #define LIBTIME_H#include <stdio.h> #include <stdlib.h>…

Unity进阶--C#补充知识点--【C#各版本的新功能新语法】C#1~4与C#5

来源于唐老狮的视频教学&#xff0c;仅作记录和感悟记录&#xff0c;方便日后复习或者查找 一.C#版本与Unity的关系 1.各Unity版本支持的C#版本 更多信息可以在Untiy官网说明查看 https://docs.unity3d.com/2020.3/Documentation/Manual/CSharpCompiler.html&#xff08;这个好…