zoukankan      html  css  js  c++  java
  • 读书笔记-深入浅出spirngboot2

    第一章

    • springboot的依赖和自动配置
    spring-boot-starter-web引入了下面的包
     <dependencies>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter</artifactId>
          <version>2.0.0.RELEASE</version>
          <scope>compile</scope>
        </dependency>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-json</artifactId>
          <version>2.0.0.RELEASE</version>
          <scope>compile</scope>
        </dependency>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-tomcat</artifactId>
          <version>2.0.0.RELEASE</version>
          <scope>compile</scope>
        </dependency>
        <dependency>
          <groupId>org.hibernate.validator</groupId>
          <artifactId>hibernate-validator</artifactId>
          <version>6.0.7.Final</version>
          <scope>compile</scope>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-web</artifactId>
          <version>5.0.4.RELEASE</version>
          <scope>compile</scope>
        </dependency>
        <dependency>https://i.cnblogs.com/EditPosts.aspx?opt=1
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>5.0.4.RELEASE</version>
          <scope>compile</scope>
        </dependency>
      </dependencies>
    

    第二章 自定义配置

    • 在运行前还需要做一些配置
      autoconfig中的配置类:
    @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
    //配置文件
    @Configuration
    //配置需要满足类型是Servlet
    @ConditionalOnWebApplication(type = Type.SERVLET)
    //需要是DispatcherServlet类
    @ConditionalOnClass(DispatcherServlet.class)
    @AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
    //自动配置servlet相关的属性,这样就能做到自动配置
    @EnableConfigurationProperties(ServerProperties.class)
    public class DispatcherServletAutoConfiguration {
    

    • 配置文件加载优先级:

    bootstrap.properties优先于application.prperties
    properties优先于yml
    resources/config优先于resources/

    第三章 全注解下的Spring IOC

    • 所有IOC容器都要实现接口BeanFactory,他是一个顶级接口
    //isSingleton判断是否单例,默认情况下bean都是单例(isSingleton返回true),如果是isPrototype返回true,则是多例模式,每次调用getBean会返回一个新的bean
    public interface BeanFactory {
    
    	String FACTORY_BEAN_PREFIX = "&";
    
    	Object getBean(String name) throws BeansException;
    	
    	<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;
    
    	Object getBean(String name, Object... args) throws BeansException;
    
    	<T> T getBean(Class<T> requiredType) throws BeansException;
    
    	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
    
    	boolean containsBean(String name);
    	
    	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
    
    	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
    
    	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
    
    	boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
    
    	@Nullable
    	Class<?> getType(String name) throws NoSuchBeanDefinitionException;
    
    	String[] getAliases(String name);
    }
    
    
    • Spring在BeanFactory的基础上,设置了一个更高级的接口ApplicationContext,他是BeanFactory的子接口之一,实际上使用的都是ApplicationContext的实现类


    • 简单注入bean的方法
    1.声明实体类
    public class User {
    	private Long id;
    	private String userName;
    	private String note;
    }
    2.增加配置类
    @Configuration
    public class AppConfig {
    	
    	@Bean(name="user")
    	public User init(){
    		User user  = new User();
    		user.setId(1L);
    		user.setUserName("aaa");
    		user.setNote("note_1");
    		return user;
    
    
    	}
    }
    3.使用
    	public static void main(String[] args) {
    		AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    		User u = (User) ctx.getBean("user");
    		System.out.println(u.getId());
    
    	}
    
    • 通过扫描注入bean
      @ComponentScan会扫描当前包和子包
    @Component("user")
    public class User {
    	private Long id;
    	private String userName;
    	private String note;
    }
    
    @Configuration
    @ComponentScan
    public class AppConfig {
    	@Bean(name="user")
    	public User init(){
    		User user  = new User();
    		user.setId(1L);
    		user.setUserName("aaa");
    		user.setNote("note_1");
    		return user;
    	}
    }
    
    	public static void main(String[] args) {
    		AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    		User u = (User) ctx.getBean(User.class);
    		System.out.println(u.getId());
    	}
    
    • ComponentScan源码
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @Documented
    //在一个类中可以重复定义
    @Repeatable(ComponentScans.class)
    public @interface ComponentScan {
    	//定义扫描的包
    	@AliasFor("basePackages")
    	String[] value() default {};
    	//定义扫描的包
    	@AliasFor("value")
    	String[] basePackages() default {};
    	//定义扫描的类
    	Class<?>[] basePackageClasses() default {};
    	//Bean name 生成器
    	Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
    	//作用域解析器
    	Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
    	//作用域代理模式
    	ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
    	//资源匹配模式
    	String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
    	//启用默认过滤器
    	boolean useDefaultFilters() default true;
    	//当满足过滤器的条件时扫描
    	Filter[] includeFilters() default {};
    	//当不满足过滤器条件时扫描
    	Filter[] excludeFilters() default {};
    	//是否延迟初始化
    	boolean lazyInit() default false;
    	//定义过滤器
    	@Retention(RetentionPolicy.RUNTIME)
    	@Target({})
    	@interface Filter {
    		//过滤器类型
    		FilterType type() default FilterType.ANNOTATION;
    		//定义过滤的类
    		@AliasFor("classes")
    		Class<?>[] value() default {};
    		//定义过滤的类
    		@AliasFor("value")
    		Class<?>[] classes() default {};
    		//匹配方式
    		String[] pattern() default {};
    	}
    }
    
    • SpringBootApplication源码
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @SpringBootConfiguration
    @EnableAutoConfiguration
    //自定义排除的扫描类
    @ComponentScan(excludeFilters = {
    		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
    public @interface SpringBootApplication {
    
    	//通过类型排除自动配置类
    	@AliasFor(annotation = EnableAutoConfiguration.class)
    	Class<?>[] exclude() default {};
    
    	//通过名称排除自动配置类
    	@AliasFor(annotation = EnableAutoConfiguration.class)
    	String[] excludeName() default {};
    
    	//定义扫描包
    	@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
    	String[] scanBasePackages() default {};
    
    	//定义被扫描的类
    	@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
    	Class<?>[] scanBasePackageClasses() default {};
    }
    
    
    • 自定义第三方bean
    Configuration
    @ComponentScan(basePackages = "com.springboot.chapter3.*", 
    excludeFilters = {@Filter(classes = {})})
    public class AppConfig {
    	
    	@Bean(name = "dataSource")
    	public DataSource getDataSource() {
    	    Properties props = new Properties();
    	    props.setProperty("driver", "com.mysql.jdbc.Driver");
    	    props.setProperty("url", "jdbc:mysql://localhost:3306/chapter3");
    	    props.setProperty("username", "root");
    	    props.setProperty("password", "123456");
    	    DataSource dataSource = null;
    	    try {
    	        dataSource = BasicDataSourceFactory.createDataSource(props);
    	    } catch (Exception e) {
    	        e.printStackTrace();
    	    }
    	    return dataSource;
    	}
    }
    

    • @AutoWired
      默认是by type注入
      如果一个接口有多个实现类,在注入时会有歧义,利用@Primary和@Quelifier可以消除歧义
      例如:


      @Primary: 当发现多个同样类型的bean时,可以优先注入
      @Quelifier: 和@AutoWired一起使用时,可以通过类型和Quelifier定义的名称一起找到bean
    • bean生命周期

      ComponentScan还有一个配置项lazyInit,只可以配置boolean值,默认是false,也就是默认不进行延迟初始化
      配置为true的话就是等到使用的时候才进行注入

    bean生命周期

    • 前和后预初始化方法(针对所有的bean都生效)
    @Component
    public class BeanPostProcessorExample implements BeanPostProcessor {
    
    	@Override
    	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    		System.out.println("BeanPostProcessor调用postProcessBeforeInitialization方法,参数【" 
    		        + bean.getClass().getSimpleName()+ "】【" +beanName+"】 ");
    		return bean;
    	}
    	
    	@Override
    	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    		System.out.println("BeanPostProcessor调用postProcessAfterInitialization方法,参数【" 
    	        + bean.getClass().getSimpleName()+ "】【" +beanName+"】 ");
    		return bean;
    	}
    
    	
    
    }
    
    • 使用属性文件
    属性文件依赖
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
    

    有了依赖,可以直接使用application.properties
    如果配置文件中是database.driverName=**这种,可以直接在配置类中使用@ConfigurationProperties( "database"),否则可以使用@Value单个属性配置
    如果不是application.properties可以使用自定义加载 @PropertySource(value={"classpath:jdbc.properties"}, ignoreResourceNotFound=true)

    • 条件装配Bean
      有时候有一些客观原因使bean无法初始化,如:在数据库连接池中漏掉一些配置使数据库连接不上,这个时候可以使用@Condition,当条件不满足的时候不加载
    加上@Conditional(DatabaseConditional.class)后,需要增加实现类,在实现类中添加过滤的规则,如果过滤的规则如果不符合则不装配这个bean
    @Bean(name = "dataSource", destroyMethod = "close")
    	@Conditional(DatabaseConditional.class)
    	public DataSource getDataSource(
    			@Value("${database.driverName}") String driver,
    			@Value("${database.url}") String url,
    			@Value("${database.username}") String username,
    			@Value("${database.password}") String password
    			) {
    		Properties props = new Properties();
    		props.setProperty("driver", driver);
    		props.setProperty("url", url);
    		props.setProperty("username", username);
    		props.setProperty("password", password);
    		DataSource dataSource = null;
    		try {
    			dataSource = BasicDataSourceFactory.createDataSource(props);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return dataSource;
    	}
    
    public class DatabaseConditional implements Condition {
    
    	@Override
    	/*
    	 * 
    	 * @param context 条件上下文
    	 * @param 
    	 */
    	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    		Environment env = context.getEnvironment();
    		return env.containsProperty("database.driverName") && env.containsProperty("database.url") 
    				&& env.containsProperty("database.username") && env.containsProperty("database.password");
    	}
    
    }
    

    Bean作用域

    • 常用bean作用域有两种: 单例和原型
    • @Profile 区分不同的环境
    @Bean(name = "dataSource", destroyMethod = "close")
    	@Profile("dev")
    	public DataSource getDevDataSource() {
    		Properties props = new Properties();
    		props.setProperty("driver", "com.mysql.jdbc.Driver");
    		props.setProperty("url", "jdbc:mysql://localhost:3306/dev_spring_boot");
    		props.setProperty("username", "root");
    		props.setProperty("password", "123456");
    		DataSource dataSource = null;
    		try {
    			dataSource = BasicDataSourceFactory.createDataSource(props);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return dataSource;
    	}
    
    
    	@Bean(name = "dataSource", destroyMethod = "close")
    	@Profile("test")
    	public DataSource getTestDataSource() {
    		Properties props = new Properties();
    		props.setProperty("driver", "com.mysql.jdbc.Driver");
    		props.setProperty("url", "jdbc:mysql://localhost:3306/test_spring_boot");
    		props.setProperty("username", "root");
    		props.setProperty("password", "123456");
    		DataSource dataSource = null;
    		try {
    			dataSource = BasicDataSourceFactory.createDataSource(props);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return dataSource;
    	}
    

    spring启动时先判断有没有spring.profiles.active,然后判断spring.profiles.default,如果这两个参数都没有配置,spring就不会启动Profile机制,被@Profile标志的bean都不会被加载

    • ImportResource 引入对应的XML文件:在配置类加上@ImportResource(value = {"classpath:spring-other.xml"})

    第五章 访问数据库

    • mybatis配置结构图

    第六章 事务处理

    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    public @interface Transactional {
    	//通过bean name指定事务管理器
    	@AliasFor("transactionManager")
    	String value() default "";
    	
    	@AliasFor("value")
    	String transactionManager() default "";
    	//指定传播行为
    	Propagation propagation() default Propagation.REQUIRED;
    	//指定隔离级别
    	Isolation isolation() default Isolation.DEFAULT;
    	//指定超时时间
    	int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
    	//只读事物
    	boolean readOnly() default false;
    	//方法发生指定异常时回滚,默认是所有都回滚
    	Class<? extends Throwable>[] rollbackFor() default {};
    	//方法发生指定异常名称时回滚,默认所有异常回滚
    	String[] rollbackForClassName() default {};
    	//方法指定异常不回滚
    	Class<? extends Throwable>[] noRollbackFor() default {};
    	//方法指定异常名称不回滚
    	String[] noRollbackForClassName() default {};
    }
    

    @Transactional 可以放在接口也可以放在实现类上,推荐放在实现类上,使用接口的话只能用jdk动态代理,不能使用CGLIB动态代理

    • 事务管理器
    • 事务隔离级别
      1.未提交读: 允许一个事务读取另外一个事务没有提交的数据(比较危险,实际很少使用,但是并发能力高),会出现脏读

    2.读写提交: 一个事务只能读取另外一个事务已经提交的数据,不能读取未提交的数据

    会出现不可重复读:

    3.可重复读:

    会出现幻读



    4.串行化:sql完全串行执行


    • 传播行为

    在spring中,当一个方法调用另外一个方法时,可以让事务采取不同的策略工作

    public enum Propagation {
    	//如果当前存在事务则沿用当前事务,否则新建一个事务运行字方法
    	REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),
    	//如果当前存在事务则沿用当前事务,否则以无事务方式运行
    	SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),
    	//必须使用事务,如果当前没有事务则抛异常,如果当前存在事务则沿用当前事务
    	MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),
    	//无论当前事务是否存在,都新建运行事务的方法,与当前事务独立
    	REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),
    	//不支持事务,如果当前有事务,则挂起事务运行方法
    	NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),
    	//不支持事务,如果当前有事务则抛异常,如果没有则继续执行
    	NEVER(TransactionDefinition.PROPAGATION_NEVER),
    	//在当前方法调用字方法时,如果子方法发生异常,只回滚子方法的sql,不回滚当前事务
    	NESTED(TransactionDefinition.PROPAGATION_NESTED);
    	private final int value;
    	Propagation(int value) { this.value = value; }
    	public int value() { return this.value; }
    }
    

    • @Transactional自调用失效
      spring事务的实现方式是AOP,AOP原理是动态代理,在自调用的过程中,是类自身的调用,而不是代理对象去调用,就不会产生AOP,
      这样Spring就不能把你的代码织入约定的流程中,为了使事务有效,要改成用一个service去调用另外一个service,这样才会触发AOP
    • 事务不生效原因汇总:
      1.没有被spring管理
      2.方法不是public,只有public的方法才会被代理
      3.自调用
      4.数据源没有配置事务管理器
      5.数据库引擎不支持事务
      6.异常被吃了,没有抛出来
      7.异常配型配置错误,默认的是RuntimeException如果想抛其他类型,加上@Transactional(rollbackFor = Exception.class)

    第七章 使用redis

    • Spring通过RedisConnection操作redis,RedisConnection是对原生的redis进行封装,要获取RedisConnection对象,需要通过RedisConnectionFactory生成
      所有使用redis的第一步是配置这个工厂,主要是配置Redis连接池
    redis依赖
    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-data-redis</artifactId>
    	<exclusions>
    		<!--不依赖Redis的异步客户端lettuce -->
    		<exclusion>
    			<groupId>io.lettuce</groupId>
    			<artifactId>lettuce-core</artifactId>
    		</exclusion>
    	</exclusions>
    </dependency>
    <!--引入Redis的客户端驱动jedis -->
    <dependency>
    	<groupId>redis.clients</groupId>
    	<artifactId>jedis</artifactId>
    </dependency>
    
    配置Redis连接池和配置RedisTemplate
    public class RedisConfig {
    
    	private RedisConnectionFactory connectionFactory = null;
    
    	@Bean(name = "redisConnectionFactory")
    	public RedisConnectionFactory initConnectionFactory() {
    		if (this.connectionFactory != null) {
    			return this.connectionFactory;
    		}
    		JedisPoolConfig poolConfig = new JedisPoolConfig();
    		// 最大空闲数
    		poolConfig.setMaxIdle(50);
    		// 最大连接数
    		poolConfig.setMaxTotal(100);
    		// 最大等待毫秒数
    		poolConfig.setMaxWaitMillis(2000);
    		// 创建Jedis连接工厂
    		JedisConnectionFactory connectionFactory = new JedisConnectionFactory(poolConfig);
    		// 配置Redis连接服务器
    		RedisStandaloneConfiguration rsc = connectionFactory.getStandaloneConfiguration();
    		rsc.setHostName("192.168.20.4");
    		rsc.setPort(6379);
    		//rsc.setPassword(RedisPassword.of("123456"));
    		this.connectionFactory = connectionFactory;
    		return connectionFactory;
    	}
    	
    	@Bean(name="redisTemplate")
    	public RedisTemplate<Object, Object> initRedisTemplate() {
    	    RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
    	    redisTemplate.setConnectionFactory(initConnectionFactory());
    	    RedisSerializer<String> stringRedisSerializer = redisTemplate.getStringSerializer();
    	    redisTemplate.setKeySerializer(stringRedisSerializer);
    	    redisTemplate.setHashKeySerializer(stringRedisSerializer);
    	    redisTemplate.setHashValueSerializer(stringRedisSerializer);
    	  return redisTemplate;
    	}
    }
    
    
    测试RedisTemplate
    	public static void main(String[] args) {
    		AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(RedisConfig.class);
    		RedisTemplate redisTemplate = ctx.getBean(RedisTemplate.class);
    		redisTemplate.opsForValue().set("key1", "value1");
    		redisTemplate.opsForHash().put("hash", "field", "hvalue");
    		ctx.close();
    	}
    


    • 如果没有配置序列化器,则默认使用JdkSerializationRedisSerializer序列化器

    • 使用字符串序列化器

    • StringRedisTemplate,继承RedisTemplate,只是提供了字符串的操作

    • Redis能支持7中数据类型
      字符串,散列,列表,集合,有序集合,基数和地理位置

    • 如果需要连续操作多个命令,则可以使用以下接口

    • springboot中使用redis
      1.配置属性

      2.修改RedisTemplate序列化器,不然就会使用默认的JdkSerializationRedisSerializer序列化器

      3.使用RedisTemplate操作数据

    • Redis事务

    • 流水线执行模式提高速度

    public Map<String, Object> testPipeline() {
    		Long start = System.currentTimeMillis();
    		List list = (List) redisTemplate.executePipelined((RedisOperations operations) -> {
    			for (int i = 1; i <= 100000; i++) {
    				operations.opsForValue().set("pipeline_" + i, "value_" + i);
    				String value = (String) operations.opsForValue().get("pipeline_" + i);
    				if (i == 100000) {
    					System.out.println("命令只是进入队列,所以值为空【" + value + "】");
    				}
    			}
    			return null;
    		});
    		Long end = System.currentTimeMillis();
    		System.out.println("耗时:" + (end - start) + "毫秒。");
    		Map<String, Object> map = new HashMap<String, Object>();
    		map.put("success", true);
    		return map;
    	}
    
    • Redis发布订阅
    消息监听器
    @Component
    public class RedisMessageListener implements MessageListener {
        @Override
        public void onMessage(Message message, byte[] pattern) {
            // 消息体
            String body = new String(message.getBody());
            // 渠道名称
            String topic = new String(pattern); 
            System.out.println(body);
            System.out.println(topic);
        }
    }
    
    	// 设置RedisTemplate的序列化器
    	private void initRedisTemplate() {
    		RedisSerializer stringSerializer = redisTemplate.getStringSerializer();
    		redisTemplate.setKeySerializer(stringSerializer);
    		redisTemplate.setHashKeySerializer(stringSerializer);
    	}
    
    	// RedisTemplate
    	@Autowired
    	private RedisTemplate redisTemplate = null;
    	
    	// Redis连接工厂
    	@Autowired
    	private RedisConnectionFactory connectionFactory = null;
    
    	// Redis消息监听器
    	@Autowired
    	private MessageListener redisMsgListener = null;
    
    	// 任务池
    	private ThreadPoolTaskScheduler taskScheduler = null;
    
    	/**
    	 * 创建任务池,运行线程等待处理Redis的消息
    	 *
    	 * @return
    	 */
    	@Bean
    	public ThreadPoolTaskScheduler initTaskScheduler() {
    		if (taskScheduler != null) {
    			return taskScheduler;
    		}
    		taskScheduler = new ThreadPoolTaskScheduler();
    		taskScheduler.setPoolSize(20);
    		return taskScheduler;
    	}
    
    	/**
    	 * 定义Redis的监听容器
    	 *
    	 * @return 监听容器
    	 */
    	@Bean
    	public RedisMessageListenerContainer initRedisContainer() {
    		RedisMessageListenerContainer container = new RedisMessageListenerContainer();
    		// Redis连接工厂
    		container.setConnectionFactory(connectionFactory);
    		// 设置运行任务池
    		container.setTaskExecutor(initTaskScheduler());
    		// 定义监听渠道,名称为topic1
    		Topic topic = new ChannelTopic("topic1");
    		// 使用监听器监听Redis的消息
    		container.addMessageListener(redisMsgListener, topic);
    		return container;
    	}
    
    	public static void main(String[] args) {
    		SpringApplication.run(Chapter7Application.class, args);
    	}
    
    

    当在redis执行publish topic1 msg时会收到信息

    • 使用lua脚本

    	public Map<String, Object> testLua2(String key1, String key2, String value1, String value2) {
    		// 定义Lua脚本
    		String lua = " redis.call('set', KEYS[1], ARGV[1]) 
    " 
    		        + " redis.call('set', KEYS[2], ARGV[2]) 
    "
    				+ " local str1 = redis.call('get', KEYS[1]) 
    " 
    		        + " local str2 = redis.call('get', KEYS[2]) 
    "
    				+ " if str1 == str2 then  
    " + "return 1 
    " 
    		        + " end 
    " 
    				+ " return 0 
    ";
    		System.out.println(lua);
    		// 结果返回为Long
    		DefaultRedisScript<Long> rs = new DefaultRedisScript<Long>();
    		rs.setScriptText(lua);
    		rs.setResultType(Long.class);
    		// 采用字符串序列化器
    		RedisSerializer<String> stringSerializer = redisTemplate.getStringSerializer();
    		// 定义key参数
    		List<String> keyList = new ArrayList<>();
    		keyList.add(key1);
    		keyList.add(key2);
    		// 传递两个参数值,其中第一个序列化器是key的序列化器,第二个序列化器是参数的序列化器
    		Long result = (Long) redisTemplate.execute(rs, stringSerializer, stringSerializer, keyList, value1, value2);
    		Map<String, Object> map = new HashMap<String, Object>();
    		map.put("result", result);
    		return map;
    	}
    

    第八章 使用MongoDb

    • 实体类加上@Document 标识为MongoDB文档
    • @Field("user_name") MongoDB一般用下划线表示字段,所以要加别名
    操作MongoDB的方法
    @Service
    public class UserServiceImpl implements UserService {
    
    	// 注入MongoTemplate对象
    	@Autowired
    	private MongoTemplate mongoTmpl = null;
    
    	@Override
    	public User getUser(Long id) {
    		return mongoTmpl.findById(id, User.class);
    		// 如果只需要获取第一个也可以采用如下查询方法
    		// Criteria criteriaId = Criteria.where("id").is(id);
    		// Query queryId = Query.query(criteriaId);
    		// return mongoTmpl.findOne(queryId, User.class);
    	}
    
    	@Override
    	public List<User> findUser(String userName, String note, int skip, int limit) {
    		// 将用户名称和备注设置为模糊查询准则
    		Criteria criteria = Criteria.where("user_name").regex(userName).and("note").regex(note);
    		// 构建查询条件,并设置分页跳过前skip个,至多返回limit个
    		Query query = Query.query(criteria).limit(limit).skip(skip);
    		// 执行
    		List<User> userList = mongoTmpl.find(query, User.class);
    		return userList;
    	}
    
    	@Override
    	public void saveUser(User user) {
    		// 使用名称为user文档保存用户信息
    		mongoTmpl.save(user, "user");
    		// 如果文档采用类名首字符小写,则可以这样保存
    		// mongoTmpl.save(user);
    	}
    
    	@Override
    	public DeleteResult deleteUser(Long id) {
    		// 构建id相等的条件
    		Criteria criteriaId = Criteria.where("id").is(id);
    		// 查询对象
    		Query queryId = Query.query(criteriaId);
    		// 删除用户
    		DeleteResult result = mongoTmpl.remove(queryId, User.class);
    		return result;
    	}
    
    	@Override
    	public UpdateResult updateUser(Long id, String userName, String note) {
    		// 确定要更新的对象
    		Criteria criteriaId = Criteria.where("id").is(id);
    		Query query = Query.query(criteriaId);
    		// 定义更新对象,后续可变化的字符串代表排除在外的属性
    		Update update = Update.update("user_name", userName);
    		update.set("note", note);
    		// 更新单个对象
    		UpdateResult result = mongoTmpl.updateFirst(query, update, User.class);
    		// 更新多个对象
    		// UpdateResult result2 = mongoTmpl.updateMulti(query, update, User.class);
    		return result;
    	}
    
    }
    
    
  • 相关阅读:
    Spring源码构建 报错exception during working with external system: java.lang.AssertionError
    EDI_了解
    前端-正则表达式-收集
    Spring Boot必备知识点
    SSM开发在线考试系统-完整版+视频教程
    基于WEB的车票预订信息系统设计
    IDEA开发Maven构建SSM项目遇到的坑,action
    Linux教程-修炼
    2020年Java 成长路线-flag
    Redis教程
  • 原文地址:https://www.cnblogs.com/Baronboy/p/14095797.html
Copyright © 2011-2022 走看看