首先添加一个空项目 选择【choose】进行下一步。设置项目名称和路径 —> 选择编译套件 --> 修改类信息 --> 完成(步骤同上),生成一个空项目。在空项目中添加文件:在项目名称上单击鼠标右键弹出右键...
首先添加一个空项目
选择【choose】进行下一步。设置项目名称和路径 —> 选择编译套件 --> 修改类信息 --> 完成(步骤同上),生成一个空项目。在空项目中添加文件:在项目名称上单击鼠标右键弹出右键菜单,选择【添加新文件】
弹出新建文件对话框
在此对话框中选择要添加的类或者文件,根据向导完成文件的添加。
在pro中添加模块
QT += widgets
在新建的main.cpp文件中
设置标题,添加按钮并指定父对象
指定父对象有两种办法:
//必须指定父对象才可以放进去
//a指定b为父对象,则a放在b上面
//制定父对象两种方式
// 1)setParent
// 1)通过构造函数传参
//制定父对象,只需要父对象显示,子对象自动显示
添加
#include#include//窗口基类对象 #includeint main(int argc,char *argv[]){ QApplication app(argc, argv); QWidget w; w.setWindowTitle("Hello World"); QPushButton b; b.setText("^_^"); //第一种 b.setParent(&w); b.move(100,100); //第二种 QPushButton b1(&w); b1.setText("按钮"); w.show(); app.exec(); return 0; }
如果没有指定父对象那么会有两个窗口。按钮为另一个窗口。
使用springboot实现读写分离这也是闲着无聊然后去了解了一下然后写了一个项目,如有不足,欢迎来指出来功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一...

使用springboot实现读写分离

这也是闲着无聊然后去了解了一下然后写了一个项目,如有不足,欢迎来指出来
因为我们读写分离至少是有两个数据源,有可能是这样的
但是我们理想的状态并不是这样,而是这种状态
这时候保证在Spring提交事务之前确定数据源,利用AOP写个切换数据源的切面,让他的优先级高于Spring事务切面的优先级。
mybatis最终是要通过sqlsessionfactory获取数据连接,创建sqlsession并提交到数据库的。所以我们入手的地方有两点:
通过创建多种sqlsessionfactory比如masterFactory,slaverFactory来实现读写分离。让sqlsessionfactory直接可以动态获取到只读或者写的数据源。
但是怎么切换数据源呢,spring中有一个AbstractRoutingDataSourc,这是DataSource的抽象,我们关注其中的四个方法
setTargetDataSources,setDefaultTargetDataSource,determineCurrentLookupKey,determineTargetDataSource,这四个方法:setTargetDataSources设置备选的数据源集合。 setDefaultTargetDataSource设置默认数据源,determineCurrentLookupKey决定当前数据源的对应的key,determineTargetDataSource方法,它才是获取数据源的实现,方法如下。
根据determineCurrentLookupKey获取的key,在resolvedDataSources这个Map中查找对应的datasource!,注意determineTargetDataSource方法竟然不使用的targetDataSources!
那一定存在resolvedDataSources与targetDataSources的对应关系。我接着翻阅代码,发现一个afterPropertiesSet方法(Spring源码中InitializingBean接口中的方法),这个方法将targetDataSources的值赋予了resolvedDataSources。源码如下:
afterPropertiesSet 方法,熟悉Spring的都知道,它在bean实例已经创建好,且属性值和依赖的其他bean实例都已经注入以后执行,也就是说调用,targetDataSources,defaultTargetDataSource的赋值一定要在afterPropertiesSet前边执行
好了,现在开始写,这里只列出部分重要代码,有兴趣可以下载项目
首先定义枚举类,
配置文件也不能少
读取配置文件
这里使用线程控制数据源切换
由于DynamicDataSource是单例的,线程不安全的,所以采用ThreadLocal保证线程安全,由DynamicDataSourceHolder完成
这里继承AbstractRoutingDataSource,并且对读进行简单的负载均衡,如果你是一个读库可以不用,判断返回当前数据源key
这里是mybatis配置,给sessionfactory设置数据源
@Configuration
@ConditionalOnClass({EnableTransactionManagement.class})
@Import({ DataBaseConfiguration.class})
public class MybatisConfiguration {
/** mybatis 配置路径 */ @Value("${spring.mybatis.configLocation:mybatis/mybatis.xml}") private String MYBATIS_CONFIG; /** mapper路径 */ @Value("${spring.mybatis.mapperLocations:mapper/*.xml}") private String MAPPER_LOCATION; @Value("${spring.datasource.type}") private ClassdataSourceType; @Value("${spring.datasource.readSize}") private String dataSourceSize; @Resource(name = "writeDataSource") private DataSource dataSource; @Resource(name = "readDataSources") private ListreadDataSources; @Bean @ConditionalOnMissingBean public SqlSessionFactory sqlSessionFactory() throws Exception { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); /** 设置mybatis configuration 扫描路径 */ sqlSessionFactoryBean.setConfigLocation(new ClassPathResource(MYBATIS_CONFIG)); sqlSessionFactoryBean.setDataSource(roundRobinDataSouceProxy()); AbstractRoutingDataSource s= roundRobinDataSouceProxy(); /** 添加mapper 扫描路径 */ sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver() .getResources(MAPPER_LOCATION)); return sqlSessionFactoryBean.getObject(); } /** * 有多少个数据源就要配置多少个bean * @return */ @Bean public AbstractRoutingDataSource roundRobinDataSouceProxy() { int size = Integer.parseInt(dataSourceSize); MyAbstractRoutingDataSource proxy = new MyAbstractRoutingDataSource(size); MaptargetDataSources = new HashMap(); // DataSource writeDataSource = SpringContextHolder.getBean("writeDataSource"); // 写targetDataSources.put(DataSourceType.write.getType(),dataSource); //1个读数据库时 // targetDataSources.put(DataSourceType.read.getType(),readDataSource); //多个读数据库时 for (int i = 0; i