zoukankan      html  css  js  c++  java
  • springboot分析——与其他组件的整合(JPA规范/atomikos/redis)

    一:与JPA规范整合

      jpa是一套orm的规范,提供api接口,hirebnate就是对jpa的一套实现,下面我们看看springboot如何

    与jpa整合

    1:添加依赖和配置

    		<!--5: 整合jpa-->
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-data-jpa</artifactId>
    		</dependency>
    

      

    #自动创建表
    spring.jpa.hibernate.ddl-auto:update
    #打印 sql 语句
    spring.jpa.show-sql:true
    

      

    2:定义service 、dao以及实体类

    @Service
    public class StudentServiceImpl implements StudentService {
    
    	@Autowired
    	private StudentDao studentDao;
    
    	@Override
    	public Student findById(Integer id) {
    		Optional<Student> optional = studentDao.findById(id);
    		if(optional.isPresent()){
    			return optional.get();
    		}
    		return null;
    	}
    
    	@Override
    	public Student insertStudent(Student student) {
    		return studentDao.save(student);
    	}
    
    }
    

      

    @Repository
    public interface StudentDao extends JpaRepository<Student,Integer> {
    
    }
    
    @Data
    @Entity
    @Table(name="student")
    public class Student {
    
    	@Id
    	@GeneratedValue(strategy = GenerationType.IDENTITY)
    	private Integer id;
    
    	@Column(name="name")
    	private String name;
    
    	@Column(name="cardId")
    	private String cardId;
    
    }
    

      

    服务启动从日志看,会创建表:

    测试类:

    生成insert语句,插入数据:

     

     与JPA整合完成,很简单

    二:与atomikos整合,实现分布式事务

      如果同时在一个方法内使用两个数据源,想实现事务,该怎么办?

    1:添加依赖和配置

    <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jta-atomikos</artifactId>
            </dependency>
    

      

    # Mysql 1
    mysql.datasource.test1.url = jdbc:mysql://localhost:3306/enjoy?useUnicode=true&characterEncoding=utf-8
    mysql.datasource.test1.username = root
    mysql.datasource.test1.password = root
    mysql.datasource.test1.minPoolSize = 3
    mysql.datasource.test1.maxPoolSize = 25
    mysql.datasource.test1.maxLifetime = 20000
    mysql.datasource.test1.borrowConnectionTimeout = 30
    mysql.datasource.test1.loginTimeout = 30
    mysql.datasource.test1.maintenanceInterval = 60
    mysql.datasource.test1.maxIdleTime = 60
    
    # Mysql 2
    mysql.datasource.test2.url =jdbc:mysql://localhost:3306/study?useUnicode=true&characterEncoding=utf-8
    mysql.datasource.test2.username =root
    mysql.datasource.test2.password =root
    mysql.datasource.test2.minPoolSize = 3
    mysql.datasource.test2.maxPoolSize = 25
    mysql.datasource.test2.maxLifetime = 20000
    mysql.datasource.test2.borrowConnectionTimeout = 30
    mysql.datasource.test2.loginTimeout = 30
    mysql.datasource.test2.maintenanceInterval = 60
    mysql.datasource.test2.maxIdleTime = 60
    
    #日志级别
    logging.level.root=info
    #所有包下面都以debug级别输出
    #logging.level.org.springframework.*=debug
    
    #sql日志
    logging.level.com.xiangxue.atomikos.db1.dao=debug
    logging.level.com.xiangxue.atomikos.db2.dao=debug
    #热部署
    #热部署生效
    spring.devtools.restart.enabled=true
    #设置重启的目录
    spring.devtools.restart.additional-paths=src/main/java
    #classpath目录下的WEB-INF文件夹内容修改不重启
    spring.devtools.restart.exclude=WEB-INF/**

    将配置封装到对象上,使用@ConfigurationProperties注解,会把mysql.datasource.test1为前缀的配置封装到对应的属性上,维护到spring

    容器缓存中

    @Data
    @ConfigurationProperties(prefix = "mysql.datasource.test1")
    public class DBConfig1 {
        private String url;
    
        private String username;
    
        private String password;
    
        private int minPoolSize;
    
        private int maxPoolSize;
    
        private int maxLifetime;
    
        private int borrowConnectionTimeout;
    
        private int loginTimeout;
    
        private int maintenanceInterval;
    
        private int maxIdleTime;
    
        private String testQuery;
    }
    

      

    创建数据源DataSource、sqlSessionFactory以及sqlSessionTemplate对象,并且添加@MapperScan扫描,将MapperFactoryBean维护到spring容器中,

    key为Mapper文件的全限定名类名,value为MapperFactoryBean对象

    @Configuration
    @MapperScan(basePackages = "com.xiangxue.jack.atomikos.db1.dao", sqlSessionFactoryRef = "test1SqlSessionFactory",sqlSessionTemplateRef="test1SqlSessionTemplate")
    public class Db1Config {
    
        @Autowired
        DBConfig1 testConfig;
    
        @Bean(name = "test1DataSource")
        public DataSource testDataSource() {
            MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
            mysqlXaDataSource.setUrl(testConfig.getUrl());
            mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
            mysqlXaDataSource.setPassword(testConfig.getPassword());
            mysqlXaDataSource.setUser(testConfig.getUsername());
            mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
    
            AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
            xaDataSource.setXaDataSource(mysqlXaDataSource);
            xaDataSource.setUniqueResourceName("test1DataSource");
            xaDataSource.setMinPoolSize(testConfig.getMinPoolSize());
            xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize());
            xaDataSource.setMaxLifetime(testConfig.getMaxLifetime());
            xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout());
            try {
                xaDataSource.setLoginTimeout(testConfig.getLoginTimeout());
            } catch (SQLException e) {
                e.printStackTrace();
            }
            xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval());
            xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime());
            xaDataSource.setTestQuery(testConfig.getTestQuery());
            return xaDataSource;
        }
    
        @Bean(name = "test1SqlSessionFactory")
        public SqlSessionFactory testSqlSessionFactory(@Qualifier("test1DataSource") DataSource dataSource)
                throws Exception {
            SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
            bean.setDataSource(dataSource);
            return bean.getObject();
        }
    
        @Bean(name = "test1SqlSessionTemplate")
        public SqlSessionTemplate testSqlSessionTemplate(
                @Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
            return new SqlSessionTemplate(sqlSessionFactory);
        }
    }
    

      

    创建Mapper类:

    public interface CommonMapper1 {
    
        @Select("select * from people")
        List<People> listPeoples();
    
        @Insert("insert into people(name) values(#{name})")
        int addPeople(People people);
    }
    

      

    另一个数据源也需要创建DataSource、SqlSessionFactory、sqlSessionTemplate对象,扫描对应的Mapper接口文件路径,和上一个数据源创建方式一样

    创建一个service的测试类:在方法上添加@Transactional注解,方法内部,两个不同的mapper新增数据,两个mapper对应不同的数据源

    @Service
    public class AreaServiceImpl implements AreaService {
    
        @Autowired
        private CommonMapper1 commonMapper1;
    
        @Autowired
        private CommonMapper2 commonMapper2;
    
        @Autowired
        TransactionManager transactionManager;
    
        @Transactional
        public int saveArea(ConsultConfigArea area) {
            System.out.println(transactionManager);
            JtaTransactionManager jtaTransactionManager = (JtaTransactionManager)transactionManager;
            System.out.println(jtaTransactionManager.getUserTransaction());
            UserTransaction userTransaction = jtaTransactionManager.getUserTransaction();
    
            People people = new People();
            people.setName("Lucy");
            int count = commonMapper1.addPeople(people);
            System.out.println("插入一条People,count:"+count);
    
            Student student = new Student();
            student.setCardId("122334");
            student.setName("hello");
            int count1 = commonMapper2.addStudent(student);
            System.out.println("插入一条Student,count1:"+count1);
            int i = 10/0;
            return count;
        }
    }
    

      

    先把会导致异常的这行代码注释掉:

     

     

     数据插入成功! 

    现在把会导致运行时异常的代码放开,看看效果

    数据没有插入,说明回滚成功!

    三:与redis整合

    1:添加依赖和配置

    		<!--6:整合redis-->
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-data-redis</artifactId>
    		</dependency>
    

      

    #Redis数据库索引(默认为0)
    spring.redis.database=0
    #redis服务器地址
    spring.redis.host=127.0.0.1
    #redis暴露端口
    spring.redis.port=6379
    #redis服务器连接密码
    spring.redis.password=
    #连接池最大连接
    spring.redis.pool.max-active=8
    #连接池最大阻塞等待时间
    spring.redis.pool.max-wait=-1
    #连接池中的最大空闲连接
    spring.redis.pool.max-idle=8
    #连接池中的最小空闲连接
    spring.redis.pool.min-idle=0
    #连接超时时间
    spring.redis.timeout=5000
    

      

    2:创建缓存管理类

    @Configuration
    @EnableCaching
    public class RedisConfig {
    
        //缓存管理器
        @Bean
        public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
            RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                    .entryTtl(Duration.ofHours(1)); // 设置缓存有效期一小时
            return RedisCacheManager
                    .builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory))
                    .cacheDefaults(redisCacheConfiguration).build();
        }
    
        @Bean
        public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
    
            RedisTemplate<String, Object> template = new RedisTemplate<>();
            // 配置连接工厂
            template.setConnectionFactory(factory);
    
            //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
            Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);
    
            ObjectMapper om = new ObjectMapper();
            // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
            om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
            om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
            jacksonSeial.setObjectMapper(om);
    
            // 值采用json序列化
            template.setValueSerializer(jacksonSeial);
            //使用StringRedisSerializer来序列化和反序列化redis的key值
            template.setKeySerializer(new StringRedisSerializer());
            // 设置hash key 和value序列化模式
            template.setHashKeySerializer(new StringRedisSerializer());
            template.setHashValueSerializer(jacksonSeial);
            template.afterPropertiesSet();
    
            return template;
        }
    }
    

      

    创建使用类:

    @Component
    public class RedisServiceImpl implements RedisService{
    
    	@Autowired
    	private UserMapper userMapper;
    
    	@Cacheable(cacheNames = "redisCache",key = "'jack'+ #id")
    	@Override
    	public String queryData(String id) {
    		System.out.println("RedisServiceImpl -- queryData");
    		List<User> list = userMapper.queryUserById(id);
    		return JSON.toJSONString(list);
    	}
    
    	@CachePut(cacheNames = "redisCache",key = "'jack'+ #id")
    	@Override
    	public String putCache(String id) {
    		System.out.println("RedisServiceImpl -- putCache");
    		User user = new User();
    		user.setName("Tom");
    		user.setAge("30");
    		user.setId(id);
    		userMapper.updateUser(user);
    		return JSON.toJSONString(user);
    	}
    }
    

     

    下面我们把redis服务器和应用启动,测试一下:

     首先查询redis缓存,缓存中没有数据,然后查询数据库,数据缓存到redis,返回数据,我们来看看redis服务器

     数据已经被放入redis缓存中,我们再次从页面查询一次:

    没有查询数据库,queryData还是上次查询数据库的日志,但是页面显示正常,说明查询的是redis服务器

    那如果我们想修改数据库的数据,会怎么样?

     我们来看看redis内存库的数据会不会变化:

    说明修改数据库的数据,redis会同步更新

    这样springboot和redis的整合就完成了!!!

  • 相关阅读:
    吴恩达机器学习笔记——梯度下降算法(2)
    吴恩达机器学习笔记——梯度下降算法(1)
    Java面向对象
    实体框架
    Android Studio 3.4.1中使用com.android.support.v4.view.ViewPager提示不存在该类或程序闪退
    7、认识 Android Service
    安卓付费课程
    在Android Studio中如何添加GSON
    android studio 添加Volley
    android studio里面怎么看file explorer啊?
  • 原文地址:https://www.cnblogs.com/warrior4236/p/13279914.html
Copyright © 2011-2022 走看看