Spring整合Redis详解

用注解驱动的方式来使用 Redis。和数据库事务一样,Spring 提供了缓存的管理器和相关的注解来支持类似于 Redis 这样的键值对缓存。

准备测试环境

首先,定义一个简单的角色 POJO,代码如下所示。

package com.pojo;
import java.io.Serializable;
public class Role implements Serializable {private static final long serialVersionUID = 3447499459461375642L;private long id;private String roleName;private String note;// 省略setter和getter方法
}

注意:该类实现了 Serializable 接口,这说明这个类支持序列化,这样就可以通过 Spring 的序列化器,将其保存为对应的编码,缓存到 Redis 中,也可以通过 Redis 读回那些编码,反序列化为对应的 Java 对象。

接下来是关于 MyBatis 的开发环境,这样我们就可以操作数据库了。创建 RoleMapper.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.dao.RoleDao"><select id="getRole" resultType="com.pojo.Role">select id, role_name asroleName, note from t_role where id = #{id}</select><delete id="deleteRole">delete from t_role where id=#{id}</delete><insert id="insertRole" parameterType="com.pojo.Role"useGeneratedKeys="true" keyProperty="id">insert into t_role (role_name,note) values(#{roleName}, #{note})</insert><update id="updateRole" parameterType="com.pojo.Role">update t_role setrole_name = #{roleName}, note = #{note} where id = #{id}</update><select id="findRoles" resultType="com.pojo.Role">select id, role_name as roleName, note from t_role<where><if test="roleName != null">role_name like concat('%', #{roleName}, '%')</if><if test="note != null">note like concat ('%', #{note},'%')</if></where></select>
</mapper>

然后,需要一个 MyBatis 角色接口,以便使用这样的一个映射文件,代码如下所示。

package com.dao;import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.pojo.Role;public interface RoleDao {public Role getRole(Long id);public int deleteRole(Long id);public int insertRole(Role role);public int updateRole(Role role);public List<Role> findRoles(@Param("roleName") String roleName, @Param("note") String note);
}

注解 @Repository 表示它是一个持久层的接口。通过扫描和注解联合定义 DAO 层,就完成了映射器方面的内容。定义角色服务接口(RoleService),代码如下所示,不过服务接口实现类会在后面谈起,因为它需要加入 Spring 缓存注解,以驱动不同的行为。

package com.service;import java.util.List;
import com.pojo.Role;public interface RoleService {public Role getRole(Long id);public int deleteRole(Long id);public Role insertRole(Role role);public int updateRole(Role role);public List<Role> findRoles(String roleName, String note);
}

通过 Java 配置定义数据库和相关的扫描内容,代码如下所示。

package com.config;import java.util.Properties;import javax.sql.DataSource;import org.apache.commons.dbcp.BasicDataSourceFactory;
import org.aspectj.apache.bcel.Repository;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;@Configuration
// 定义Spring扫描的包
@ComponentScan("com.*")
// 使用事务驱动管理器
@EnableTransactionManagement
// 实现接口 TransactionManagementConfigurer,这样可以配置注解驱动事务
public class RootConfig implements TransactionManagementConfigurer {private DataSource dataSource = null;/*** 配置数据库** @return数据连接池*/@Bean(name = "dataSource")public DataSource initDataSource() {if (dataSource != null) {return dataSource;}Properties props = new Properties();props.setProperty("driverClassName", "com.mysql.jdbc.Driver");props.setProperty("url", "jdbc:mysql://localhost:3306/redis");props.setProperty("username", "root");props.setProperty("password", "1128");try {dataSource = BasicDataSourceFactory.createDataSource(props);} catch (Exception e) {e.printStackTrace();}return dataSource;}/*** 配置 SqlSessionFactoryBean** @return SqlSessionFactoryBean*/@Bean(name = "SqlSessionFactory")public SqlSessionFactoryBean initSqlSessionFactory() {SqlSessionFactoryBean SqlSessionFactory = new SqlSessionFactoryBean();SqlSessionFactory.setDataSource(initDataSource());// 配置MyBatis配置文件Resource resource = new ClassPathResource("mybatis/mybatis-config.xml");SqlSessionFactory.setConfigLocation(resource);return SqlSessionFactory;}/*** 通过自动扫描,发现MyBatis Mapper接口** @return Mapper 扫描器*/@Beanpublic MapperScannerConfigurer initMapperScannerConfigurer() {MapperScannerConfigurer msc = new MapperScannerConfigurer();// 扫描包msc.setBasePackage("com.*");msc.setSqlSessionFactoryBeanName("SqlSessionFactory");// 区分注解扫描msc.setAnnotationClass(Repository.class);return msc;}/*** 实现接口方法,注册注解事务,当@Transactional使用的时候产生数据库事务*/@Override@Bean(name = "annotationDrivenTransactionManager")public PlatformTransactionManager annotationDrivenTransactionManager() {DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();transactionManager.setDataSource(initDataSource());return transactionManager;}
}

在 SqlSessionFactoryBean 的定义中引入了关于 MyBatis 的一个配置文件——mybatis-config.xml,它放在源码的 mybatis 目录之下,它的作用是引入 RoleMapper.xml,我放在目录 com/dao 下,代码如下所示。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><mappers><mapper resource="com/dao/RoleMapper.xml" /></mappers>
</configuration>

这样测试只要一个 RoleService 实现类就可以了,这个类的实现就是我们后面所需要讨论的主要的内容,不过在此之前要先了解 Spring 的缓存管理器。

Spring 的缓存管理器

在 Spring 项目中它提供了接口 CacheManager 来定义缓存管理器,这样各个不同的缓存就可以实现它来提供管理器的功能了,而在 spring-data-redis.jar 包中实现 CacheManager 接口的则是 RedisCacheManager,因此要定义 RedisCacheManager 的 Bean,不过在此之前要先定义 RedisTemplate。

下面使用注解驱动 RedisCacheManager 定义,代码如下所示。

package com.config;import java.util.ArrayList;
import java.util.List;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;import redis.clients.jedis.JedisPoolConfig;@Configuration
@EnableCaching
public class RedisConfig {@Bean(name = "redisTemplate")public RedisTemplate initRedisTemplate() {JedisPoolConfig poolConfig = new JedisPoolConfig();// 最大空闲数poolConfig.setMaxIdle(50);// 最大连接数poolConfig.setMaxTotal(100);// 最大等待亳秒数poolConfig.setMaxWaitMillis(20000);// 创建Jedis连接工厂JedisConnectionFactory connectionFactory = JedisConnectionFactory(poolConfig);connectionFactory.setHostName("localhost");connectionFactory.setPort(6379);// 调用后初始化方法,没有它将抛出异常connectionFactory.afterPropertiesSet();// 自定Redis序列化器RedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer();RedisSerializer stringRedisSerializer = new StringRedisSerializer();// 定义RedisTemplate,并设置连接工程RedisTemplate redisTemplate = new RedisTemplate();redisTemplate.setConnectionFactory(connectionFactory);// 设置序列化器redisTemplate.setDefaultSerializer(stringRedisSerializer);redisTemplate.setKeySerializer(stringRedisSerializer);redisTemplate.setValueSerializer(jdkSerializationRedisSerializer);redisTemplate.setHashKeySerializer(stringRedisSerializer);redisTemplate.setHashValueSerializer(jdkSerializationRedisSerializer);return redisTemplate;}@Bean(name = "redisCacheManager")public CacheManager initRedisCacheManager(@Autowired RedisTemplate redisTempate) {RedisCacheManager cacheManager = new RedisCacheManager(redisTempate);// 设置超时时间为10分钟,单位为秒cacheManager.setDefaultExpiration(600);// 设置缓存名称List<String> cacheNames = new ArrayList<String>();cacheNames.add("redisCacheManager");cacheManager.setCacheNames(cacheNames);return cacheManager;}
}

@EnableCaching 表示 Spring IoC 容器启动了缓存机制。对于 RedisTemplate 的定义实例和 XML 的方式差不多。注意,在创建 Jedis 连接工厂(JedisConnectionFactory)后,要自己调用其 afterPropertiesSet 方法,因为这里不是单独自定义一个 Spring Bean,而是在 XML 方式中是单独自定义的。

这个类实现了 InitializingBean 接口,按照 Spring Bean 的生命周期,我们知道它会被 Spring IoC 容器自己调用,而这里的注解方式没有定义 SpringBean,因此需要自己调用。

字符串定义了 key(包括 hash 数据结构),而值则使用了序列化,这样就能够保存 Java 对象了。

缓存管理器 RedisCacheManager 定义了默认的超时时间为 10 分钟,这样就可以在一定的时间间隔后重新从数据库中读取数据了,而名称则定义为 redisCacheManager,名称是为了方便后面注解引用的。

这里只定义 RedisCacheManager,使用 XML 定义缓存管理器代码如下所示。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xmlns:cache="http://www.springframework.org/schema/cache"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/cachehttp://www.springframework.org/schema/cache/spring-cache.5.0.xsd"><!--使用注解驱动,其中属性cache-manager默认值为cacheManager, 所以如果你的缓存管理器名称也是cacheManager则无需重新定义 --><cache:annotation-driven cache-manager="redisCacheManager" /><!-- 定义缓存管理器,如果你使用id="cacheManager",则驱动不需要显式配置cache-manager属性 --><bean id="redisCacheManager"class="org.springframework.data.redis.cache.RedisCacheManager"><!--通过构造方法注入RedisTemplate --><constructor-arg index="0" ref="redisTemplate" /><!-- 定义默认超时时间,单位秒 --><property name="defaultExpiration" value="600" /><!--缓存管理器名称 --><property name="cacheNames"><list><value>redisCacheManager</value></list></property></bean>
</beans>

这样也可以配置好对应的缓存管理器。

缓存注解简介

配置了缓存管理器之后,Spring 就允许用注解的方式使用缓存了,这里的注解有 4 个。XML 也可以使用它们,但是用得不多,我们就不再介绍了,还是以注解为主。首先简介一下缓存注解,如下表所示。

缓存注解

注 解描 述
@Cacheable表明在进入方法之前,Spring 会先去缓存服务器中査找对应 key 的缓存值,如果找到缓存值,那么 Spring 将不会再调用方法,而是将缓存值读出,返回给调用者;如果没有找到缓存值,那么 Spring 就会执行你的方法,将最后的结果通过 key 保存到缓存服务器中
@CachePutSpring 会将该方法返回的值缓存到缓存服务器中,这里需要注意的是,Spring 不会事先去缓存服务器中查找,而是直接执行方法,然后缓存。换句话说,该方法始终会被 Spring 所调用
@CacheEvict移除缓存对应的 key 的值
@Caching这是个分组注解,它能够同时应用于其他缓存的注解

注解 @Cacheable 和 @CachePut 都可以保存缓存键值对,只是它们的方式略有不同,请注意二者的区别,它们只能运用于有返回值的方法中,而删除缓存 key 的 @CacheEvict 则可以用在 void 的方法上,因为它并不需要去保存任何值。

上述注解都能标注到类或者方法之上,如果放到类上,则对所有的方法都有效;如果放到方法上,则只是对方法有效。在大部分情况下,会放置到方法上。因为 @Cacheable 和 @CachePut 可以配置的属性接近,所以把它们归为一类去介绍,而 @Caching 不常用。

一般而言,对于查询,我们会考虑使用 @Cacheable;对于插入和修改,我们会考虑使用 @CachePut;对于删除操作,我们会考虑使用 @CacheEvict。

注解@Cacheable和@CachePut

因为 @Cacheable 和 @CachePut 两个注解的配置项比较接近,所以这里就将这两个注解一并介绍了,它们的属性,如下表所示。

@Cacheable 和 @CachePut 配置属性
在这里插入图片描述
其中,因为 value 和 key 这两个属性使用得最多,所以先来讨论这两个属性。value 是一个数组,可以引用多个缓存管理器。

比如使用注解驱动 RedisCacheManager 定义代码中所定义的 RedisCacheManager,就可以引用它了,而对于 key 则是缓存中的键,它支持 Spring 表达式,通过 Spring 表达式就可以自定义缓存的 key。编写剩下的 RoleService 接口的实现类——RoleServiceImpl 的方法。

先了解一些 Spring 表达式和缓存注解之间的约定,通过这些约定去引用方法的参数和返回值的内容,使得其注入 key 所定义的 Spring 表达式的结果中,表达式值的引用如下表所示。

表达式值的引用
在这里插入图片描述

这样就方便使用对应的参数或者返回值作为缓存的 key 了。

RoleService 接口的实现类——RoleServiceImpl,它有 3 个方法,使用这个缓存可以启动缓存管理器来保存数据,代码如下所示。

package com.service;import java.util.List;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;import com.dao.RoleDao;
import com.pojo.Role;@Service
public class RoleServiceImpl implements RoleService {
//角色DAO,方便执行SQL@Autowiredprivate RoleDao roleDao = null;/*** 使用@Cacheable定义缓存策略 当缓存中有值,则返回缓存数据,否则访问方法得到数据 通过value引用缓存管理器,通过key定义键** @param id角色编号* @return 角色*/@Override@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)@Cacheable(value = "redisCacheManager", key = "'redis_role_'+#id")public Role getRole(Long id) {return roleDao.getRole(id);}/*** 使用@CachePut则表示无论如何都会执行方法,最后将方法的返回值再保存到缓存中 使用在插入数据的地方,则表示保存到数据库后,会同期插入Redis缓存中** @param role角色对象 @return角色对象(会回填主键)*/@Override@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)@CachePut(value = "redisCacheManager", key = "'redis_role_'+#resuIt.id")public Role insertRole(Role role) {roleDao.insertRole(role);return role;}/*** 使用@CachePut,表示更新数据库数据的同时,也会同步更新缓存** @param role角色对象* @return影响条数*/@Override@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)@CachePut(value = "redisCacheManager", key = "'redis_role_' +#role. id")public Role updateRole(Role role) {roleDao.updateRole(role);return role;}......
}

因为 getRole 方法是一个查询方法,所以使用 @Cacheable 注解,这样在 Spring 的调用中,它就会先查询 Redis,看看是否存在对应的值,那么采用什么 key 去查询呢?

注解中的 key 属性,它配置的是 ‘redis_role_’+#id,这样 Spring EL 就会计算返回一个 key,比如参数 id 为 1L,其 key 计算结果就为 redis_role_1。以一个 key 去访问 Redis,如果有返回值,则不再执行方法,如果没有则访问方法,返回角色信息,然后通过 key 去保存数据到 Redis 中。

先执行 insertRole 方法才能把对应的信息保存到 Redis 中,所以采用的是注解 @CachePut。由于主键是由数据库生成,所以无法从参数中读取,但是可以从结果中读取,那么 #result.id 的写法就会返回方法返回的角色 id。而这个角色 id 是通过数据库生成,然后由 MyBatis 进行回填得到的,这样就可以在 Redis 中新增一个 key,然后保存对应的对象了。

对于 updateRole 方法而言,采用的是注解 @CachePut,由于对象有所更新,所以要在方法之后更新 Redis 的数据,以保证数据的一致性。这里直接读取参数的 id,所以表达式写为 #role.id,这样就可以引入角色参数的 id 了。在方法结束后,它就会去更新 Redis 对应的 key 的值了。

为此可以提供一个 log4j.properties 文件来监控整个过程:

# Global logging configuration
log4j.rootLogger=DEBUG,stdout
# MyBatis logging configuration...
log4j.logger.com.mybatis=DEBUG
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

然后通过以下代码来测试缓存注解。

// 使用注解Spring IoC容器
ApplicationContext ctx = new AnnotationConfigApplicationContext(RootConfig.class, RedisConfig.class);
// 获取角色服务类
RoleService roleService = ctx.getBean(RoleService.class);
Role role = new Role();
role.setRoleName("role_name_1");
role.setNote("role_note_1");
// 插入角色
roleService.insertRole(role);
// 获取角色
Role getRole = roleService.getRole(role.getId());
getRole.setNote("role_note_1_update");
// 更新角色
roleService.updateRole(getRole);

将关于数据库和 Redis 的相关配置通过注解 Spring IoC 容器加载进来,这样就可以用 Spring 操作这些资源了,然后执行插入、获取、更新角色的方法。

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

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

相关文章

Redis和数据库的结合

使用 Redis 可以优化性能&#xff0c;但是存在 Redis 的数据和数据库同步的问题&#xff0c;这是我们需要关注的问题。假设两个业务逻辑都是在操作数据库的同一条记录&#xff0c;而 Redis 和数据库不一致。 Redis 和数据库不一致 在图中&#xff0c;T1 时刻以键 key1 保存数…

C 字符串排序

使用C语言对字符串进行排序 编写程序对字符串进行排序输出&#xff0c;用户根据提示输入三个字符串&#xff0c;程序根据26个英文字母的顺序进行排序输出。 完整代码 #include<stdio.h> #include<stdlib.h> #include <string.h>void swap(char*str1,char*…

plsql连接报ORA-12537

客户新电脑装上了plsql&#xff0c;连接数据库时报如上错误&#xff0c;但是别的电脑都可以正常连接&#xff0c;先检查了下TNS配置&#xff0c;发现没问题&#xff0c;数据库连接数也足够&#xff0c;百思不得其解 后面去数据库服务器上查看了监听日志文件&#xff0c;连接报错…

C 将任意八进制数转化为十进制

C语言实现八进制数到十进制的转化 使用C语言将一个八进制数转化为十进制数&#xff0c;用户根据提示输入一个任意的八进制数&#xff0c;程序将八进制数转化为十进制数并进行输出显示。 完整代码 #include<stdio.h> #include<stdlib.h> int main() {int n0,i0;c…

C 字符串连结

C语言实现对两个字符串进行连接 用户根据提示分别输如两个任意的字符串&#xff0c;两个字符串之间要用回车分开&#xff0c;程序将这两个字符串进行连接并输出显示。 完整代码 #include <stdio.h> #include<stdlib.h> #include<string.h>char* strconnec…

C 时间函数

C获取当前时间并进行输出 使用C语言的时间函数获取当前的时间并输出显示在控制台。 完整代码 #include <stdio.h> #include <time.h>int main () {time_t rawtime;struct tm * timeinfo;time ( &rawtime );timeinfo localtime ( &rawtime );printf ( &…

C 猜谜游戏

C语言实现猜谜游戏 利用C语言的判断循环&#xff0c;以及获取值实现猜谜游戏&#xff0c;用户根据提示输入任意数据&#xff0c;程序会获取你输入的数据并判断大小给出提示&#xff0c;用户再次输入数据经过若干次循环判断使用户猜出正确的答案。 完整代码 #include <std…

pycharm创建我的第一个项目

使用pycharm创建我的第一个项目 1 . Create New Project 2 . pycharm设置项目的保存位置&#xff08;创建的是一个空项目&#xff09;。 3 . 添加python文件&#xff0c;右击项目文件夹 --> New --> python File。 4 . 设置创建的python文件名称&#xff0c;点击下方…

Pycharm 字体大小及背景颜色的设置

设置Pycharm 的字体大小及背景颜色 Pycharm设置字体的大小及风格 选择File --> setting --> Editor --> Font,我们可以看到如下图所示界面&#xff0c;我们就可以根据自己的喜好随意调整字体的大小&#xff0c;字体的样式风格&#xff0c;文字行间距&#xff0c;设置…

pycharm设置开发模板

pycharm设置开发模板 可能大家会有一些疑问&#xff0c;什么是模板&#xff1f;为什么要设置模板的呢&#xff1f;模板就是一种通用的格式&#xff0c;如果在pycharm中设置了模板&#xff0c;那么每次创建一个python文件的时候都会自动包含模板中的内容。 示例 python3 默认采…

Webstorm设置开发模板

WebStorm设置开发模板 可能大家会有一些疑问&#xff0c;什么是模板&#xff1f;为什么要设置模板的呢&#xff1f;模板就是一种通用的格式&#xff0c;如果在webstorm中设置了模板&#xff0c;那么每次创建一个javaScript文件的时候都会自动包含模板中的内容。 我们想要Webs…

Pycharm 项目运行的多种技巧

当我们在pycharm上完成我们的项目之后&#xff0c;我们应该如何运行这个项目的呢&#xff1f; 方法一&#xff1a;点击三角线绿色按钮&#xff0c;运行run&#xff08;运行程序&#xff09; 方法二&#xff1a;使用快捷键 Ctrl shift 10 &#xff0c;效果一样&#xff0c;同…

C++ 输入输出

C实现获取用户输入的数值并进行输出显示。 完整代码 #include <iostream> using namespace std;int main() { int number;cout << "输入一个整数: ";cin >> number;cout << "输入的数字为: " << number; return 0; …

C++ 求和运算

C实现对两个数字进行相加并输出显示结果。 根据提示输入两个数&#xff0c;程序获取两个数的数值并且执行加法运算&#xff0c;在控制台输出显示两个数相加的结果。 完整代码 #include <iostream> using namespace std;int main() {int firstNumber, secondNumber, su…

C++ 奇偶判断

C实现对数字奇偶进行判断 根据提示输入任意一个数字&#xff0c;程序获取内容之后进行相关的判断并根据判断结果进行输出。 方法一&#xff1a;使用if else判断 #include <iostream> using namespace std;int main() {int n;cout << "输入一个整数: "…

C++ 判断元音/辅音

C判断元音还是辅音&#xff0c;并输出在控制台上。 我们知道英语有 26 个字母&#xff0c;元音只包括 a、e、i、o、u 这五个字母&#xff0c;其余的都为辅音。y是半元音、半辅音字母&#xff0c;但在英语中都把他当作辅音。 用户根据提示输入任意字母&#xff0c;程序判断输入…

C++ 求一元二次方程的根

C计算并输出一元二次方程的根 二次方程 ax2bxc 0 (其中a≠0&#xff09;&#xff0c;a 是二次项系数&#xff0c;bx 叫作一次项&#xff0c;b是一次项系数&#xff1b;c叫作常数项。 x 的值为&#xff1a; 根的判别式 示例 #include <iostream> #include <cmat…

C++三角形合集

C输出各种样式的三角形 *示例一&#xff08;号直角三角形&#xff09; #include <iostream> using namespace std;int main() {int rows;cout << "输入行数: ";cin >> rows;for(int i 1; i < rows; i){for(int j 1; j < i; j){cout <…

C++ 简单计算器

C实现简单的计算器 实现一个简单的计算器&#xff0c;可以实现对数字的加减乘除运算并输出显示结果。 完整代码 #include <iostream> using namespace std;int main() {char op;float num1, num2;cout << "输入运算符&#xff1a;、-、*、/ : ";cin &…

java版本查看

我们应该如何查看我们当前使用的java版本的呢&#xff1f;&#xff1f;&#xff1f; 我们可以使用 -version 来查看当前Java的运行版本&#xff0c;命令如下所示&#xff1a; java -version详细步骤 1 . winR然后输如 cmd 打开我们的控制台。 2 . 在控制台输入java -versio…