SpringBootDruid多数据源Atomikos

多数据源

导入依赖

<!-- MySql驱动 -->
<dependency> <groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency>
<!-- 连接池 -->
<dependency> <groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.9</version>
</dependency>

修改配置文件

我这里是配置了五个数据源 ttxnsaasaccount,ttxnsaasproject,ttxnsaassys,ttxnsaasexam,ttxnsaasorders

spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.jdbc.Driverdruid:ttxnsaasaccount:url: jdbc:mysql://127.0.0.1:3306/ttxnsaasaccount?characterEncoding=UTF-8&useUnicode=true&useSSL=falseusername: rootpassword: rootttxnsaasproject:url: jdbc:mysql://127.0.0.1:3306/ttxnsaasproject?characterEncoding=UTF-8&useUnicode=true&useSSL=falseusername: rootpassword: rootttxnsaassys:url: jdbc:mysql://127.0.0.1:3306/ttxnsaassys?characterEncoding=UTF-8&useUnicode=true&useSSL=falseusername: rootpassword: rootttxnsaasexam:url: jdbc:mysql://127.0.0.1:3306/ttxnsaasexam?characterEncoding=UTF-8&useUnicode=true&useSSL=falseusername: rootpassword: rootttxnsaasorders:url: jdbc:mysql://127.0.0.1:3306/ttxnsaasorders?characterEncoding=UTF-8&useUnicode=true&useSSL=falseusername: rootpassword: root

定义数据库名称常量

/*** @author 萧一旬* @date Create in 10:58 2020/7/13* <p>* 数据库名称*/
public interface DataSourceNames {String TTXN_SAAS_ACCOUNT = "TTXN_SAAS_ACCOUNT";String TTXN_SAAS_PROJECT = "TTXN_SAAS_PROJECT";String TTXN_SAAS_EXAM = "TTXN_SAAS_EXAM";String TTXN_SAAS_ORDERS = "TTXN_SAAS_ORDERS";String TTXN_SAAS_SYS = "TTXN_SAAS_SYS";
}

创建动态数据源

/*** 动态数据源** @author 萧一旬* @date Create in 11:00 2020/7/13*/
public class DynamicDataSource extends AbstractRoutingDataSource {private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();/*** 配置DataSource, defaultTargetDataSource为主数据库*/public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {super.setDefaultTargetDataSource(defaultTargetDataSource);super.setTargetDataSources(targetDataSources);super.afterPropertiesSet();}@Overrideprotected Object determineCurrentLookupKey() {return getDataSource();}public static void setDataSource(String dataSource) {contextHolder.set(dataSource);}public static String getDataSource() {return contextHolder.get();}public static void clearDataSource() {contextHolder.remove();}
}

配置动态数据源

/*** @author 萧一旬* @date Create in 11:02 2020/7/13*/
@Configuration
public class DynamicDataSourceConfig {/*** 创建 DataSource Bean*/@Bean(name = "ttxnSaasAccountDataSource")@ConfigurationProperties(prefix = "spring.datasource.druid.ttxnsaasaccount")public DataSource ttxnSaasAccountDataSource() {DataSource dataSource = DruidDataSourceBuilder.create().build();return dataSource;}@Bean(name = "ttxnSaasProjectDataSource")@ConfigurationProperties("spring.datasource.druid.ttxnsaasproject")public DataSource ttxnSaasProjectDataSource() {DataSource dataSource = DruidDataSourceBuilder.create().build();return dataSource;}/*** @return*/@Bean(name = "ttxnSaasExamDataSource")@ConfigurationProperties("spring.datasource.druid.ttxnsaasexam")public DataSource ttxnSaasExamDataSource() {DataSource dataSource = DruidDataSourceBuilder.create().build();return dataSource;}@Bean(name = "ttxnSaasOrdersDataSource")@ConfigurationProperties("spring.datasource.druid.ttxnsaasorders")public DataSource ttxnSaasOrdersDataSource() {DataSource dataSource = DruidDataSourceBuilder.create().build();return dataSource;}@Bean(name = "ttxnSaasSysDataSource")@ConfigurationProperties("spring.datasource.druid.ttxnsaassys")public DataSource ttxnSaasSysDataSource() {DataSource dataSource = DruidDataSourceBuilder.create().build();return dataSource;}/*** 如果还有数据源,在这继续添加 DataSource Bean*/@Bean@Primarypublic DynamicDataSource dataSource(DataSource ttxnSaasAccountDataSource,DataSource ttxnSaasProjectDataSource,DataSource ttxnSaasExamDataSource,DataSource ttxnSaasOrdersDataSource,DataSource ttxnSaasSysDataSource) {Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put(DataSourceNames.TTXN_SAAS_ACCOUNT, ttxnSaasAccountDataSource);targetDataSources.put(DataSourceNames.TTXN_SAAS_EXAM, ttxnSaasExamDataSource);targetDataSources.put(DataSourceNames.TTXN_SAAS_ORDERS, ttxnSaasOrdersDataSource);targetDataSources.put(DataSourceNames.TTXN_SAAS_PROJECT, ttxnSaasProjectDataSource);targetDataSources.put(DataSourceNames.TTXN_SAAS_SYS, ttxnSaasSysDataSource);// 还有数据源,在targetDataSources中继续添加System.out.println("DataSources:" + targetDataSources);return new DynamicDataSource(ttxnSaasAccountDataSource, targetDataSources);}}

定义动态数据源注解

/*** @author 萧一旬* @date Create in 11:02 2020/7/13*/
@Documented
@Target({java.lang.annotation.ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {String value();
}

数据源AOP代理

/*** 数据源AOP切面处理** @author 萧一旬* @date Create in 11:22 2020/7/13*/@Aspect
@Component
@Slf4j
public class DataSourceAspect implements Ordered {/*** 切点: 所有配置 DataSource 注解的方法*/@Pointcut("@annotation(com.ttxn.common.data.DataSource)")public void dataSourcePointCut() {}@Around("dataSourcePointCut()")public Object around(ProceedingJoinPoint point) throws Throwable {MethodSignature signature = (MethodSignature) point.getSignature();Method method = signature.getMethod();DataSource ds = method.getAnnotation(DataSource.class);// 通过判断 DataSource 中的值来判断当前方法应用哪个数据源DynamicDataSource.setDataSource(ds.value());System.out.println("当前数据源: " + ds.value());log.debug("set datasource is " + ds.value());try {return point.proceed();} finally {DynamicDataSource.clearDataSource();log.debug("clean datasource");}}@Overridepublic int getOrder() {return 1;}
}

修改启动类

/*** 项目启动类*/
//@SpringBootApplication
@EnableSwagger2
//动态数据源配置,需要将自有的配置依赖(DynamicDataSourceConfig),将原有的依赖去除(DataSourceAutoConfiguration)
@Import({DynamicDataSourceConfig.class})
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class CompanyMainApplication {public static void main(String[] args) {
//      System.setProperty("spring.devtools.restart.enabled", "false");SpringApplication.run(CompanyMainApplication.class, args);}
}

测试

只需要在方法上加上我们的自定义注解,并指定好数据源即可

@Override
@DataSource(DataSourceNames.TTXN_SAAS_ACCOUNT)
public Integer selectNewAccountCount() {return this.baseMapper.selectNewAccountCount();
}@Override
@DataSource(DataSourceNames.TTXN_SAAS_ACCOUNT)
public Integer queryAccountStudentPendingCount(Integer companyId) {return this.baseMapper.queryAccountStudentPendingCount(companyId);
}

多数据源事务处理

当配置了多数据源之后,原来单数据源的事务就不起作用了,甚至还会引起报错,所以使用的时候要把原来加的@Transactional注解全部删掉

Atomikos

导入依赖

<dependency><groupId>com.atomikos</groupId><artifactId>transactions</artifactId><version>4.0.6</version>
</dependency>
<dependency><groupId>com.atomikos</groupId><artifactId>transactions-api</artifactId><version>4.0.6</version>
</dependency>
<dependency><groupId>com.atomikos</groupId><artifactId>transactions-jta</artifactId><version>4.0.6</version>
</dependency>
<dependency><groupId>com.atomikos</groupId><artifactId>transactions-jdbc</artifactId><version>4.0.6</version>
</dependency>
<dependency><groupId>com.atomikos</groupId><artifactId>atomikos-util</artifactId><version>4.0.6</version>
</dependency><dependency><groupId>javax.transaction</groupId><artifactId>javax.transaction-api</artifactId><version>1.2</version>
</dependency>

修改多数据源配置类

DynamicDataSourceConfig代码修改一下

@Data
public class DbConfig implements Serializable {private static final long serialVersionUID = 1L;private String url;private String username;private String password;
}-------------------------------
/*** @author 萧一旬* @date Create in 11:02 2020/7/13*/
@Configuration
public class DynamicDataSourceConfig {@Bean("accountConfig")@ConfigurationProperties(prefix = "spring.datasource.druid.ttxnsaasaccount")public DbConfig accountConfig() {return new DbConfig();}/*** 创建 DataSource Bean*/@Bean(name = "ttxnSaasAccountDataSource")public DataSource ttxnSaasAccountDataSource(@Qualifier("accountConfig") DbConfig accountConfig) {
//        DataSource dataSource = DruidDataSourceBuilder.create().build();MysqlXADataSource mysqlXADataSource = new MysqlXADataSource();mysqlXADataSource.setUrl(accountConfig.getUrl());mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);mysqlXADataSource.setPassword(accountConfig.getPassword());mysqlXADataSource.setUser(accountConfig.getUsername());AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();atomikosDataSourceBean.setXaDataSource(mysqlXADataSource);atomikosDataSourceBean.setUniqueResourceName("ttxnSaasAccountDataSource");return atomikosDataSourceBean;
//        return dataSource;}@Bean("projectConfig")@ConfigurationProperties("spring.datasource.druid.ttxnsaasproject")public DbConfig projectConfig() {return new DbConfig();}@Bean(name = "ttxnSaasProjectDataSource")public DataSource ttxnSaasProjectDataSource(@Qualifier("projectConfig") DbConfig projectConfig) {MysqlXADataSource mysqlXADataSource = new MysqlXADataSource();mysqlXADataSource.setUrl(projectConfig.getUrl());mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);mysqlXADataSource.setPassword(projectConfig.getPassword());mysqlXADataSource.setUser(projectConfig.getUsername());AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();atomikosDataSourceBean.setXaDataSource(mysqlXADataSource);atomikosDataSourceBean.setUniqueResourceName("ttxnSaasProjectDataSource");return atomikosDataSourceBean;}@Bean("examConfig")@ConfigurationProperties("spring.datasource.druid.ttxnsaasexam")public DbConfig examConfig() {return new DbConfig();}@Bean(name = "ttxnSaasExamDataSource")public DataSource ttxnSaasExamDataSource(@Qualifier("examConfig") DbConfig examConfig) {MysqlXADataSource mysqlXADataSource = new MysqlXADataSource();mysqlXADataSource.setUrl(examConfig.getUrl());mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);mysqlXADataSource.setPassword(examConfig.getPassword());mysqlXADataSource.setUser(examConfig.getUsername());AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();atomikosDataSourceBean.setXaDataSource(mysqlXADataSource);atomikosDataSourceBean.setUniqueResourceName("ttxnSaasExamDataSource");return atomikosDataSourceBean;}@Bean("ordersConfig")@ConfigurationProperties("spring.datasource.druid.ttxnsaasorders")public DbConfig ordersConfig() {return new DbConfig();}@Bean(name = "ttxnSaasOrdersDataSource")public DataSource ttxnSaasOrdersDataSource(@Qualifier("ordersConfig") DbConfig ordersConfig) {MysqlXADataSource mysqlXADataSource = new MysqlXADataSource();mysqlXADataSource.setUrl(ordersConfig.getUrl());mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);mysqlXADataSource.setPassword(ordersConfig.getPassword());mysqlXADataSource.setUser(ordersConfig.getUsername());AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();atomikosDataSourceBean.setXaDataSource(mysqlXADataSource);atomikosDataSourceBean.setUniqueResourceName("ttxnSaasOrdersDataSource");return atomikosDataSourceBean;}@Bean("sysConfig")@ConfigurationProperties("spring.datasource.druid.ttxnsaassys")public DbConfig sysConfig() {return new DbConfig();}@Bean(name = "ttxnSaasSysDataSource")public DataSource ttxnSaasSysDataSource(@Qualifier("sysConfig") DbConfig sysConfig) {MysqlXADataSource mysqlXADataSource = new MysqlXADataSource();mysqlXADataSource.setUrl(sysConfig.getUrl());mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);mysqlXADataSource.setPassword(sysConfig.getPassword());mysqlXADataSource.setUser(sysConfig.getUsername());AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();atomikosDataSourceBean.setXaDataSource(mysqlXADataSource);atomikosDataSourceBean.setUniqueResourceName("ttxnSaasSysDataSource");return atomikosDataSourceBean;}/*** 如果还有数据源,在这继续添加 DataSource Bean*/@Bean@Primarypublic DynamicDataSource dataSource(DataSource ttxnSaasAccountDataSource,DataSource ttxnSaasProjectDataSource,DataSource ttxnSaasExamDataSource,DataSource ttxnSaasOrdersDataSource,DataSource ttxnSaasSysDataSource) {Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put(DataSourceNames.TTXN_SAAS_ACCOUNT, ttxnSaasAccountDataSource);targetDataSources.put(DataSourceNames.TTXN_SAAS_EXAM, ttxnSaasExamDataSource);targetDataSources.put(DataSourceNames.TTXN_SAAS_ORDERS, ttxnSaasOrdersDataSource);targetDataSources.put(DataSourceNames.TTXN_SAAS_PROJECT, ttxnSaasProjectDataSource);targetDataSources.put(DataSourceNames.TTXN_SAAS_SYS, ttxnSaasSysDataSource);// 还有数据源,在targetDataSources中继续添加System.out.println("DataSources:" + targetDataSources);return new DynamicDataSource(ttxnSaasAccountDataSource, targetDataSources);}}

配置多数据源的事务处理

/****  分布式事物管理*/
@Configuration
public class AutoProxyRegist {@Bean(name="atomikosTransactionManager",initMethod="init",destroyMethod="close")public UserTransactionManager userTransactionManager(){UserTransactionManager transactionManager = new UserTransactionManager();transactionManager.setForceShutdown(false);return transactionManager;}@Bean(name="atomikosUserTransaction")public UserTransactionImp userTransactionImp() throws SystemException {UserTransactionImp transactionImp = new UserTransactionImp();transactionImp.setTransactionTimeout(120);return transactionImp;}@Bean("springTransactionManager")public JtaTransactionManager transactionManager(@Qualifier("atomikosTransactionManager") UserTransactionManager transactionManager,@Qualifier("atomikosUserTransaction") UserTransactionImp userTransaction) {JtaTransactionManager jtaTM = new JtaTransactionManager();jtaTM.setTransactionManager(transactionManager);jtaTM.setUserTransaction(userTransaction);jtaTM.setAllowCustomIsolationLevels(true);return jtaTM;}@Bean(name = "txAdvice")public TransactionInterceptor getAdvisor(@Qualifier("springTransactionManager") JtaTransactionManager txManager)throws Exception {TransactionInterceptor tsi = new TransactionInterceptor();Properties properties = new Properties();properties.setProperty("get*", "PROPAGATION_SUPPORTS");properties.setProperty("select*", "PROPAGATION_SUPPORTS");properties.setProperty("load*", "PROPAGATION_SUPPORTS");properties.setProperty("query*", "PROPAGATION_SUPPORTS");properties.setProperty("list*", "PROPAGATION_SUPPORTS");properties.setProperty("add*", "PROPAGATION_REQUIRED");properties.setProperty("insert*", "PROPAGATION_REQUIRED");properties.setProperty("save*", "PROPAGATION_REQUIRED");properties.setProperty("update*", "PROPAGATION_REQUIRED");properties.setProperty("modify*", "PROPAGATION_REQUIRED");properties.setProperty("do*", "PROPAGATION_REQUIRED");properties.setProperty("del*", "PROPAGATION_REQUIRED");properties.setProperty("remove*", "PROPAGATION_REQUIRED");properties.setProperty("process*", "PROPAGATION_REQUIRED");properties.setProperty("create*", "PROPAGATION_REQUIRED");properties.setProperty("valid*", "PROPAGATION_REQUIRED");properties.setProperty("do*", "PROPAGATION_REQUIRED");properties.setProperty("write*", "PROPAGATION_REQUIRED");properties.setProperty("cancel*", "PROPAGATION_REQUIRED");properties.setProperty("*", "readOnly");tsi.setTransactionAttributes(properties);tsi.setTransactionManager(txManager);return tsi;}@Beanpublic BeanNameAutoProxyCreator txProxy() {BeanNameAutoProxyCreator creator = new BeanNameAutoProxyCreator();creator.setInterceptorNames("txAdvice");creator.setBeanNames("*ServiceImpl");creator.setProxyTargetClass(true);return creator;}
}

注意

当你只有一个模块配置了atomikos的话,这样子就可以了,但是如果多项目都配置了atomikos,那么只能启动一个项目,第二个项目启动就会报错 com.atomikos.icatch.SysException: Error in init(): Log already in use 这个问题是因为每个项目输出日志的文件不能是同一个,也就是文件名com.atomikos.icatch.log_base_name不能重复

所以还需要在使用到的每个项目里加上一个配置文件transactions-defaults.properties

#===============================================================
#============          事务管理器(TM)配置参数       ==============
#===============================================================
#指定是否启动磁盘日志,默认为true。在生产环境下一定要保证为true,否则数据的完整性无法保证
com.atomikos.icatch.enable_logging=true
#JTA/XA资源是否应该自动注册
com.atomikos.icatch.automatic_resource_registration=true
#JTA事务的默认超时时间,默认为10000ms
com.atomikos.icatch.default_jta_timeout=10000
#事务的最大超时时间,默认为300000ms。这表示事务超时时间由 UserTransaction.setTransactionTimeout()较大者决定。4.x版本之后,指定为0的话则表示不设置超时时间
com.atomikos.icatch.max_timeout=300000
#指定在两阶段提交时,是否使用不同的线程(意味着并行)。3.7版本之后默认为false,更早的版本默认为true。如果为false,则提交将按照事务中访问资源的顺序进行。
com.atomikos.icatch.threaded_2pc=false
#指定最多可以同时运行的事务数量,默认值为50,负数表示没有数量限制。在调用 UserTransaction.begin()方法时,可能会抛出一个”Max number of active transactions reached”异常信息,表示超出最大事务数限制
com.atomikos.icatch.max_actives=50
#是否支持subtransaction,默认为true
com.atomikos.icatch.allow_subtransactions=true
#指定在可能的情况下,否应该join 子事务(subtransactions),默认值为true。如果设置为false,对于有关联的不同subtransactions,不会调用XAResource.start(TM_JOIN)
com.atomikos.icatch.serial_jta_transactions=true
#指定JVM关闭时是否强制(force)关闭事务管理器,默认为false
com.atomikos.icatch.force_shutdown_on_vm_exit=false
#在正常关闭(no-force)的情况下,应该等待事务执行完成的时间,默认为Long.MAX_VALUE
com.atomikos.icatch.default_max_wait_time_on_shutdown=9223372036854775807#===============================================================
#=========        事务日志(Transaction logs)记录配置       =======
#===============================================================
#事务日志目录,默认为./。
com.atomikos.icatch.log_base_dir=./
#事务日志文件前缀,默认为tmlog。事务日志存储在文件中,文件名包含一个数字后缀,日志文件以.log为扩展名,如tmlog1.log。遇到checkpoint时,新的事务日志文件会被创建,数字增加。
com.atomikos.icatch.log_base_name=tmlog
#指定两次checkpoint的时间间隔,默认为500
com.atomikos.icatch.checkpoint_interval=500#===============================================================
#=========          事务日志恢复(Recovery)配置       =============
#===============================================================
#指定在多长时间后可以清空无法恢复的事务日志(orphaned),默认86400000ms
com.atomikos.icatch.forget_orphaned_log_entries_delay=86400000
#指定两次恢复扫描之间的延迟时间。默认值为与com.atomikos.icatch.default_jta_timeout相同
com.atomikos.icatch.recovery_delay=${com.atomikos.icatch.default_jta_timeout}
#提交失败时,再抛出一个异常之前,最多可以重试几次,默认值为5
com.atomikos.icatch.oltp_max_retries=5
#提交失败时,每次重试的时间间隔,默认10000ms
com.atomikos.icatch.oltp_retry_interval=10000===============================================================
=========          其他       =============================== ==
===============================================================
java.naming.factory.initial=com.sun.jndi.rmi.registry.RegistryContextFactory
com.atomikos.icatch.client_demarcation=false
java.naming.provider.url=rmi://localhost:1099
com.atomikos.icatch.rmi_export_class=none
com.atomikos.icatch.trust_client_tm=false

SpringBoot--Druid多数据源配置相关推荐

  1. springboot动态多数据源配置和使用(二)

    很久之前写一篇静态的springboot多数据源配置,一直没写下篇,这里补充一下自己用动态多数据源的场景和开发逻辑. 之前说的静态多数据源是每个数据源配置一套mapper,现在说说如何动态多数据源共用 ...

  2. springboot动态多数据源配置和使用(从数据库读取数据源配置)(三)

    上两遍已经描述了动态多数据源的原理和基础实现了,前面的数据源配置都是从application.yml中配置多数据源的,这里再拓展补充一下其他场景,如何读取数据源不从application.yml中配置 ...

  3. druid多数据源配置

    druid多数据源配置 一.配置yml 二.数据源配置类 三.使SpringBoot不创建默认的DataSource 一.配置yml spring:#1.JDBC数据源datasource:druid ...

  4. springboot+dynamic多数据源配置

    springboot+dynamic多数据源配置 配置 使用 springboot+dynamic多数据源配置 来源:https://mp.baomidou.com/guide/dynamic-dat ...

  5. SpringBoot Redis多数据源配置

    个人博客纯净版 SpringBoot Redis多数据源配置 | 代码搬运工 此处提供了一个SpringBoot starter插件 gitee地址 spring-boot-starter-dynam ...

  6. spring+druid多数据源配置

    博客引用处(以下内容在原有博客基础上进行补充或更改,谢谢这些大牛的博客指导): spring+druid多数据源配置 druid多数据源配置 一.druid简介 Druid首先是一个数据库连接池,但它 ...

  7. springboot+mybatis多数据源配置

    目录 1.前言 2.多数据源配置 2.1  AbstractRoutingDataSource 2.2.首先maven依赖 2.3 数据源配置 2.4 mybatis配置 2.5 设置数据源的路由ke ...

  8. spring boot +spring data jpa +druid 多数据源配置

    一.首先pom.xml新增如下依赖 <dependencies><dependency><groupId>org.springframework.boot</ ...

  9. SpringBoot mybatis多数据源配置,记录下我磕磕碰碰的三个月找工作经历

    */ public class DynamicDataSource extends AbstractRoutingDataSource { /** 取得当前使用哪个数据源 @return */ @Ov ...

  10. SpringBoot2/SpringBoot/Java动态数据源配置、动态连接池配置、多数据源负载均衡

    Java动态数据源配置.动态连接池配置.多数据源负载均衡 大家好,今天给大家推荐一个自产的连接池插件.废话不多说,本文接口分为以下主题: 1. 插件开发背景: 2. 插件提供的能力: 3. 插件的使用 ...

最新文章

  1. Blockchain与Big Data将碰撞出怎样的火花?
  2. python项目实战:20行代码画一朵好看又有趣的小花花
  3. Curl 采集乱码 gzip 原因及解决方案 utf-8
  4. 最简单的制作从USB启动的系统的方法
  5. Vaadin Flow –奇妙的鹿
  6. Android 使用SeekBar调节系统音量
  7. ucos-II之就绪表解读
  8. 在pcduino开发板上写驱动控制板载LED的闪烁
  9. 换服务器原网站数据会丢失吗,ecs服务器更换操作系统后原服务器数据还在吗?...
  10. java网上销售外文文献_基于java网上购物论文英文的参考文献欣赏
  11. VC++进行ActiveX控件的开发
  12. php sql注入防御方法,SQL注入防御的方法有哪些
  13. 复选框点击后弹出输入框
  14. 论文阅读《SHINE: Signed Heterogeneous Information Network Embedding for Sentiment Link Prediction》
  15. Java 每半年就会更新一次新特性,再不掌握就要落伍了:Java16 的新特性
  16. 文献综述格式及写作技巧
  17. 采访:新浪微博架构师兼首席PHP技术顾问惠新宸谈PHP的架构与发展
  18. python语言流程控制语句的格式_慢步学python,编程基础知识,流程控制语句if
  19. win 10系统安装DBC2000时卡死的解决方法
  20. nema23_57步进电机其实就是NEMA23电机

热门文章

  1. JavaScript 把字符串类型转换成日期类型
  2. PLSQL导出Oracle表结构
  3. PAT1127 如何根据后序遍历中序遍历建树?
  4. Android入门之TabHost,TabWidget
  5. 关于PHP中Session文件过多的问题
  6. 『高级篇』docker容器来说什么是微服务(三)
  7. ListView的操作模式的选择的更详细的解释CHOICE_MODE_MULTIPLE与CHOICE_MODE_MULTIPLE_MODAL...
  8. Domino/Xpages Bootstrap 动态生成首页功能
  9. LeoFS —— 高可靠性的分布式对象存储系统
  10. tfs连不上团队资源管理器问题