精华内容
下载资源
问答
  • 1、多数据源与动态数据源 当项目不只是要用到一个数据库的时候就需要使用到多个数据源了,这种场景很多,比如要查找的数据不在同一个数据库库中,或者是要做数据库读写分离。应对上面的问题主要有两种解决方法。 ...

    1、多数据源与动态数据源

    当项目不只是要用到一个数据库的时候就需要使用到多个数据源了,这种场景很多,比如要查找的数据不在同一个数据库库中,或者是要做数据库读写分离。应对上面的问题主要有两种解决方法。

    第一种:在Spring中注入多个DataSource,然后根据不同的DataSource生成不同的SqlSessionFactory,把要操作不同数据库的mapper接口放在不同的包下,并且使用MyBatis的@MapperScan注解,使用不同的SqlSessionFactory扫描不同包下的mapper接口。

    例如:

    第一步:向Spring中注入多个数据源
    @Bean("db1-DataSource")
    @Primary//注意这个@Primary注解是必须的,必须要有一个数据源加上这个注解,否则SpringBoot无法启动
    @ConfigurationProperties(prefix = "datasource.db1")
    fun db1DataSource(): DataSource {
        return DataSourceBuilder.create().build()
    }
    
    @Bean("db2-DataSource")
    @ConfigurationProperties(prefix = "datasource.db2")
    fun db2DataSource(): DataSource {
        return DataSourceBuilder.create().build()
    }
    
    第二步:生成多个SqlSessionFactory并注入Spring
    @Bean("db1-SqlSessionFactory")
    fun db1SqlSessionFactory(@Qualifier("db1-DataSource") ds: DataSource): SqlSessionFactory {
        val fb = SqlSessionFactoryBean()
        fb.setDataSource(ds)
        fb.setMapperLocations("你的mapper的xml文件位置")
        return fb.getObject()
    }
    
    @Bean("db2-SqlSessionFactory")
    fun db2SqlSessionFactory(@Qualifier("db2-DataSource") ds: DataSource): SqlSessionFactory {
        val fb = SqlSessionFactoryBean()
        fb.setDataSource(ds)
        fb.setMapperLocations("你的mapper的xml文件位置")
        return fb.getObject()
    }
    
    第三步:@MapperScan使用不同的SqlSessionFactory扫描不同包下的mapper接口生成代理对象,假设要操作db1数据库的mapper接口放在app.mapper.db1包下,要操作db2数据库的mapper接口放在app.mapper.db2包下
    
    @MapperScan(value = ["app.mapper.db1"], sqlSessionFactoryRef = "db1-SqlSessionFactory")
    
    @MapperScan(value = ["app.mapper.db2"], sqlSessionFactoryRef = "db2-SqlSessionFactory")
    
    这样不同包下的mapper接口就可以操作不同的数据库了。

    接下来详细介绍第二种方法。

    第二种:使用Spring提供的动态数据源AbstractRoutingDataSource

    AbstractRoutingDataSource是一个抽象类,他实现了DataSource接口,内部可以存放多个DataSource,可以在需要的时候返回不同的DataSource。

    接下来解析AbstractRoutingDataSource的部分源码:

    //AbstractRoutingDataSource的内部使用了一个map存放多个数据源,key是数据源的唯一名字(可以任意命名,但是要保证唯一),value是对应的DataSource
    
    private Map<Object, Object> targetDataSources;
    //提供一个默认使用的数据源
    private Object defaultTargetDataSource;
    
    //这个是我们要实现的一个抽象方法,返回值是DataSource的唯一名字,表示使用该名字对应的DataSource
    protected abstract Object determineCurrentLookupKey();
    //这个是决定使用哪个数据源的方法,根据determineCurrentLookupKey的返回值来决定
    protected DataSource determineTargetDataSource() {
        Object lookupKey = determineCurrentLookupKey();
    	DataSource dataSource = this.resolvedDataSources.get(lookupKey);
    	if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
    		dataSource = this.resolvedDefaultDataSource;
    	}
    
    	if (dataSource == null) {
    		throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
    	}
    
    	return dataSource;
    }
    //可以设置存放多个数据源的map
    public void setTargetDataSources(Map<Object, Object> targetDataSources) {
       this.targetDataSources = targetDataSources;
    }
    
    //设置默认的数据源
    public void setDefaultTargetDataSource(Object defaultTargetDataSource) {
    	this.defaultTargetDataSource = defaultTargetDataSource;
    }

    我们要做的就是继承这个AbstractRoutingDataSource抽象类,并且实现determineCurrentLookupKey() 这个方法,通过返回值来动态改变需要使用的数据源。

    现在来假设一种应用场景,我们需要拦截标注了@Transactional注解的方法,如果这个方法是以"add"、"update"、 "delete",作为前缀,那么就使用db1-DataSource,如果是以 "get" 做为前缀,则使用db2-DataSource。这相当于进行了一个简单的读写分离。

    也就是说我们需要在标注了@Transactional注解的事务方法执行之前,根据方法签名去动态改变使用的DataSource。

    这里可以编写一个切面去拦截该要执行的事务方法,然后在切面当中去判断执行的方法名,将获取的结果信息保存在一个ThreradLocal当中,这样就可以在AbstractRoutingDataSource的determineCurrentLookupKey方法中从ThreadLocal中获取这个信息并且返回对应的数据源的名字。使用ThreadLocal的主要原因是因为事务方法总是并发执行的,为了防止相互的干扰。

    具体的示例代码如下:

    我编写了一个DynamicDataSource去继承了AbstractRoutingDataSource,并且实现了determineCurrentLookupKey方法。

    class DynamicDataSource : AbstractRoutingDataSource() {
        override fun determineCurrentLookupKey(): Any {
            //这个MultipleDataSourceConfig是配置了多个数据源、sqlSessionFactory等的一个配置类
            val key = MultipleDataSourceConfig.threadLocal.get()
    
            println(" DynamicDataSource 当前使用的数据库为 : ${key} ")
    
            if (key == null) {
                println("error dataSource key ")
                return "db1"//这个是默认数据源的key
            }
    
            return key
        }
    }

    这个是配置类。

    EnableTransactionManagement
    @Configuration
    open class MultipleDataSourceConfig {
    
        companion object {
            val threadLocal: ThreadLocal<String> = ThreadLocal()
        }
    
        @Bean("db1-DataSource")
        @Primary
        open fun masterDataSource(): DataSource? {
            根据配置信息返回一个数据源
        }
    
        @Bean("db2-DataSource")
        open fun masterDataSource(): DataSource? {
            根据配置信息返回一个数据源
        }
    
    
        @Bean("dataSource")
        open fun dataSource(@Qualifier("db1-DataSource") db1: DataSource, @Qualifier("db2-DataSource") db2: DataSource): DynamicDataSource {
            val map = 把db1与db2放入一个map当中,key是db1和db2,value是对应的数据源
            return DynamicDataSource().apply {
                this.setTargetDataSources(map)
                this.setDefaultTargetDataSource(db1)
            }
        }
    
        @Bean("sqlSessionFactory")
        open fun sqlSessionFactory(@Qualifier("dataSource") ds: DataSource): SqlSessionFactory {
            val bean = SqlSessionFactoryBean()
            bean.setDataSource(ds)
            return bean.getObject()
        }
    
        @Bean
        open fun transactionManager(@Qualifier("dataSource") ds: DataSource): DataSourceTransactionManager {
            return DataSourceTransactionManager(ds)
        }
    }

    这个是拦截事务方法的切面。

    @Component
    @Aspect
    @Order(1)//这个注解的作用稍后会进行讲解
    class SelectDataSourceAspect {
    
       @Before("@annotation(org.springframework.transaction.annotation.Transactional)")
        fun before(jp: JoinPoint) {
            println(" SelectDataSourceAspect 拦截的方法名为 ${jp.signature.name} ")
    
            try {
                println(" SelectDataSourceAspect 执行${jp.signature.name}方法 : 事务已经开启 -> " + TransactionInterceptor.currentTransactionStatus().toString())
                //println(TransactionInterceptor.currentTransactionStatus().toString() + " " + txm)
            } catch (e: Exception) {
                println(" SelectDataSourceAspect 执行${jp.signature.name}方法 : 事务没有开启 ")
            }
    
            if (如果 jp.signature.name 是以add、update、delete作为前缀) {
                MultipleDataSourceConfig.threadLocal.set("db1")
            } else {
                MultipleDataSourceConfig.threadLocal.set("db2")
            }
        }
    
    }

    到这里好像看起来没问题,但是有一个重大的bug。

    Spring当中有一个事务切面来帮我们处理事务方法,他主要是在事务方法执行之前从数据源中拿取connection,设置开启事务,如果成功执行则提交,抛出异常则回滚(具体的源码在Spring的事务管理器DataSourceTransactionManager中)。

    而我们的切面是要在事务方法执行之前进行使用数据源判断的,也就是是说这两个切面是有执行的先后顺序的。

    例如:假设开始的时候Spring的事务切面先执行,他从数据源中拿取connection,因为ThreadLocal当中没有值,所以拿取到的connection是默认数据源db1的,在他拿取connection之后我们才改变了使用的数据源,这个显然是错误的。

    那么如何改变切面的执行顺序呢?

    查阅官方文档有这样的一段描述:

    点我跳转:Spring关于切面执行顺序的描述

    大致内容就是可以给切面加上@Order注解,@Order注解内部有一个int类型的值表示优先级,该值越小则切面越优先被执行。

    因此给我们配置的切面加上@Order(1)注解,就可以保证我们的优先执行了。

    这就是第二种方法的全部内容以及一些注意事项。

    说明:

    1、并不是一定要使用AOP来判断使用的数据源,你可以在filter、controller、controller的拦截器等等 当中进行判断。

    2、示例当中通过方法名来判断使用的数据源显然不是很优美,你可以编写一个自己的注解,例如@Read、@Write,然后在AOP中获取Method,利用反射拿出注解内容再进行判断,这样的话代码也会好看很多。注意:只有环绕的通知(@Around)才能拿到Method,像前置通知@Before只能拿到方法签名。

    2、运行时动态添加数据源

    针对上面使用的spring动态数据源,我有一个突发奇想,能不能在项目运行的时候添加数据源呢?也就是在不需要停止web应用的情况的通过网络传输一些数据源的配置信息给web应用,然后web应用就可以使用这个新加数据源操作对应的数据库。

    我们前面提到的AbstractRoutingDataSource中使用了[Map<Object, Object> targetDataSources]来保存多个数据源,考虑在运行的时候往这个map里面put新的数据源就可以。

    在具体的实现上,发送数据源配置信息我决定使用apollo,在apollo上添加的配置会同步到web应用中,当然你可以使用其他的方法,比如通过controller接受数据源配置或者通过dubbo这样的rpc框架、或者是写个listener监听端口使用原生的socket进行信息传输等等,喜欢那种就用那种。我使用apollo主要因为,我的项目的配置信息全部放在apollo上进行了统一管理。

    使用一个ConcureentHashMap来存放这些数据源,把它注册进Spring的容器当中,并且通过setTargetDataSources方法set进AbstractRoutingDataSource中。使用ConcureentHashMap而不使用HashMap的主要是因为增加数据源操作和事务切面获取数据源操作之间可能会有并发执行的情况,为了线程安全考虑。

    代码示例如下:

    向Spring中注入一个ConcureentHashMap

    @Bean("slaves")
    open fun runtimeDataSource(): ConcurrentHashMap<Any, Any> {
        val map = ConcurrentHashMap<Any, Any>()
        val cfg = ConfigService.getAppConfig()
        val set = cfg.propertyNames
        for (key in set) {
            //配置的前缀是db.slave.,这里是获取已经配置了的数据源
            if (key.startsWith("db.slave.")) {
                val value = cfg.getProperty(key, "")
                //编写一个getDataSource方法解析自定义的配置,kv中key表示数据源的名字,value表示数据源。
                val kv = getDataSource(key, value)
                if (kv != null) {
                    map.put(kv.key, kv.value)
                }
            }
        }
    
        //这里是监听随时通过网络发送过来的数据源配置
        cfg.addChangeListener(ConfigChangeListener { changeEvent ->
            //使用同步方法的主要原因是,把更新后的数据及时刷新回主存当中。
            //因为执行synchronized之前,需要的数据会从主存中获取而不是缓存中获取,执行完成之后会及时的刷新回主存。(周志明的深入理解jvm中有提到)
            //而且也是防止一次性添加多个数据源并发的时候发生一些错误。
            synchronized(this) {
                for (key in changeEvent.changedKeys()) {
                    val change = changeEvent.getChange(key)
                    if (change.changeType.equals(PropertyChangeType.ADDED) && change.propertyName.startsWith("db.slave.")) {
                        //编写一个getDataSource方法解析自定义的配置,kv中key表示数据源的名字,value表示数据源。
                        val kv = getDataSource(change.propertyName, change.newValue)
                        if (kv != null) {
                            //把数据源put进行map当中
                            map.put(kv.key, kv.value)
                        }
                    }
                }
            }
        })
    
        return map
    }

    在我们的切面当中注入这个map。

    @Component
    @Aspect
    @Order(1)
    class SelectDataSourceAspect {
        @Autowired
        @Qualifier("slaves")
        lateinit var dbs: ConcurrentHashMap<Any, Any>
    
        @Before("@annotation(org.springframework.transaction.annotation.Transactional)")
        fun before(jp: JoinPoint) {
            println(" SelectDataSourceAspect 拦截的方法名为 ${jp.signature.name} ")
    
            try {
                println(" SelectDataSourceAspect 执行${jp.signature.name}方法 : 事务已经开启 -> " + TransactionInterceptor.currentTransactionStatus().toString())
            } catch (e: Exception) {
                println(" SelectDataSourceAspect 执行${jp.signature.name}方法 : 事务没有开启 ")
            }
    
            val methodName = jp.signature.name
    
            if (methodName 是一个add、updat、delete方法 || dbs.size == 1) {
                MultipleDataSourceConfig.threadLocal.set("db1")
            } else {
                val li = mutableListOf<String>()
                for (k in dbs.keys) {
                    if (!"db1".equals(k.toString())) {
                        li.add(k.toString())
                    }
                }
    
                //如果是读取方法则随便从其他的数据源当中返回一个。
                //读写分离,写的话必须走主库,读的话随便挑一个从库。
                //当然可以编写更有效率的路由选择算法来替换这个随机选择算法。
                val idx = Math.abs(random.nextInt()) % li.size
                MultipleDataSourceConfig.threadLocal.set(li[idx])
            }
    
    
        }
    
    }

    DynamicDataSource中的代码保持不变,只需要从ThreadLocal中获取只然后返回就可以了。

    但是!测试的发现并不会选择到动态添加的数据源,只有提前配置好的数据源才可以,但是DynamicDataSource中已经返回了正确的数据源的key。

    打开AbstractRoutingDataSource源码查看选择数据源的过程:

    //可以看到,获取connection是从一个determineTargetDataSource返回的数据源中拿的
    @Override
    public Connection getConnection() throws SQLException {
    	return determineTargetDataSource().getConnection();
    }
    
    //这个determineTargetDataSource是根据determineCurrentLookupKey返回的key来获取数据源
    //但是!他是从resolvedDataSources中获取的,那么这个resolvedDataSources又是从哪里来的呢?
    protected DataSource determineTargetDataSource() {
    	Object lookupKey = determineCurrentLookupKey();
    	DataSource dataSource = this.resolvedDataSources.get(lookupKey);
    	if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
    		dataSource = this.resolvedDefaultDataSource;
    	}
    	if (dataSource == null) {
    		throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
    	}
    	return dataSource;
    }
    
    //原来resolvedDataSources只是从targetDataSources中copy了一份过去而已
    @Override
    public void afterPropertiesSet() {
    	if (this.targetDataSources == null) {
    		throw new IllegalArgumentException("Property 'targetDataSources' is required");
    	}
    	this.resolvedDataSources = new HashMap<Object, DataSource>(this.targetDataSources.size());
    	for (Map.Entry<Object, Object> entry : this.targetDataSources.entrySet()) {
    		Object lookupKey = resolveSpecifiedLookupKey(entry.getKey());
    		DataSource dataSource = resolveSpecifiedDataSource(entry.getValue());
    		this.resolvedDataSources.put(lookupKey, dataSource);
    	}
    	if (this.defaultTargetDataSource != null) {
    		this.resolvedDefaultDataSource = resolveSpecifiedDataSource(this.defaultTargetDataSource);
    	}
    }
    

    知道原因之后就可以进行修改了,干脆在DynamicDataSource把determineTargetDataSource方法也重写了,然后从注入的map当中选择数据源,就不用通过resolvedDataSources获取了。

    修改后的DynamicDataSource代码如下:

    class DynamicDataSource : AbstractRoutingDataSource() {
    
        @Autowired
        @Qualifier("slaves")
        lateinit var dbs: ConcurrentHashMap<Any, Any>
    
        override fun determineCurrentLookupKey(): Any {
            val key = MultipleDataSourceConfig.threadLocal.get()
    
            if (key == null) {
                println("error dataSource key ")
                return "db1"
            }
    
            return key
        }
    
        //重写这个方法,其实这个在父类中是protect,这是一个很明显的提示
        override fun determineTargetDataSource(): DataSource? {
            val lookupKey = determineCurrentLookupKey()
            var dataSource = dbs[lookupKey]
    
            if (dataSource is DataSource) {
                return dataSource
            }
    
            return null
        }
    
    }

    到此整个过程就分享完毕了,我进行了一些场景的测试都得到了正确的结果。

    3、工程的源代码

    代码托管在github上面:工程源码

    展开全文
  • 动态加载数据源关键一点:在系统运行时加载多一个数据源,加载此数据源的对象必须和系统启动时加载数据源的同一个,在我这里加载数据源的对象是类DynamicDataSource,可在这里添加一个加载数据源的方法: ...
  • 什么是动态数据类型

    千次阅读 2016-07-02 13:02:45
    动态数据类型 Python是动态数据类型,变量不需要指定类型。 Python的变量,可变的是指向,不可通过变量名修改其指向数据单元的内容。 //函数id() 的作用是查看变量指向的内存地址。见help(id) //内存中...

    动态数据类型

    Python是动态数据类型,变量不需要指定类型。

    Python的变量,可变的是指向,不可通过变量名修改其指向数据单元的内容。

    //函数id() 的作用是查看变量指向的内存地址。见help(id)
    //内存中分配两个单元,存放数字12和13。
    //x,y分别指向内存地址,类似C语言的指针
    x=12
    y=13
    print 'x=',x,id(x)
    print 'y=',y,id(y)
    //让x指向y的地址
    x=y
    print 'x=',x,id(x)
    print 'y=',y,id(y)
    //内存中分配两个单元,存放数字15和16。
    x=15
    y=16
    print 'x=',x,id(x)
    print 'y=',y,id(y)
    运行结果:
    x= 12166579468
    y= 13 166579456
    x= 13 166579456
    y= 13 166579456
    x= 15 166579432
    y= 16 166579420

    可以看到变量x和y指向的内存单元在不断的变化。

    而某个内存单元中的数据内容是固定不变的,例如内存单元 166579468 始终保存数据12,直到程序结束,释放空间 。

    Python变量的类型是根据它所指向的内存单元中的数据类型决定的,因此不需要声明,指向什么类型,就是什么类型。

    C语言的静态数据类型

    #include <stdio.h>
    int main(int argc,char * argv[]){
    int x=12, y=13;
    //%d输出整数,%p输出指针
    printf("x=%d,x_addr = %p\n",x,&x);
    printf("y=%d,y_addr = %p\n",y,&y);
    x=y;
    printf("x=%d,x_addr = %p\n",x,&x);
    printf("y=%d,y_addr = %p\n",y,&y);
    //把变量x指向的内存单元中的数据缓存15
    x=15;
    y=16;
    printf("x=%d,x_addr = %p\n",x,&x);
    printf("y=%d,y_addr = %p\n",y,&y);
    return 0;
    }
    运行程序:
    //CentOS安装gcc
    $sudo yum install gcc
    //编译.c文件,生成myapp文件
    $gcc -o myapp dataType.c
    //运行myapp
    $./myapp

    运行结果:

    x=12,x_addr = 0xbfd9014c
    y=13,y_addr = 0xbfd90148
    x=13,x_addr = 0xbfd9014c
    y=13,y_addr = 0xbfd90148
    x=15,x_addr = 0xbfd9014c
    y=16,y_addr = 0xbfd90148

    和Python的情况相反,变量x,y的指向不变,例如变量x一直指向0xbfd9014c 内存单元。

    而变化的一直是变量指向的内存中的数据内容。

    C语言声明一个int类型的变量,即分配一块内存空间给这个变量。

    这个内存单元始终属于这个变量,且只能存放int类型的数据,直到释放内存。

    静态类型语言声明变量时必须指明数据类型,因为要为每个变量提前分配好固定大小的内存空间

    总结:

    动态语言(又称弱类型语言),变量不用声明类型,具体类型根据指向的内存单元中的数据类型决定。

    动态类型,指向可变,内存单元中的数据不可变。

    静态语言(又称强类型语言),变量需要声明类型,变量指向的内存单元可存放的数据类型固定。

    静态类型,内容可变,变量的指向不可变。


    展开全文
  • 一、datagrid动态数据加载easyui datagrid实现动态加载数据,通常有两种方式。一种方式是通过动态改变datagrid的url属性,进行数据重载;另一种方式,是通过ajax动态加载json数据。1、改变url属性重载数据。var url=...

    一、datagrid动态数据加载

    easyui datagrid实现动态加载数据,通常有两种方式。一种方式是通过动态改变datagrid的url属性,进行数据重载;另一种方式,是通过ajax动态加载json数据。

    1、改变url属性重载数据。

    var url='./data.php?act=get_hwkc';
    $('#dg').datagrid('options').url=url;
    $('#dg').datagrid('reload');

     

    2、ajax动态加载json数据

     

    $.ajax({
    	type: 'POST',
    	url:'./data.php?act=get_hwkc',
    	data: {id:'001'},
    	dataType: 'json',
    	error: function(){
    		return false;
    	},
    	success:function(json)
    	{
    		$("#dg").datagrid("loadData", json);
    	    alert("加载成功!");
    	}
    });
    

     

    二、datagrid数据清空

     

    将datagrid赋值空数据,实现如下:

    $("#dg").datagrid("loadData", { total: 0, rows: [] });
    /*或者*/
    $("#dg").datagrid("loadData", []);

     

    展开全文
  • 动态数据结构

    千次阅读 2016-12-19 12:06:24
    所谓动态数据结构,是指在运行时刻才能确定所需内存空间大小的数据结构,动态数据结构所使用的的内存称为动态内存。动态内存的使用有一定的危险,必须遵守一定的规则。动态申请的内存在不需要时必须及时释放,如果...

            所谓动态数据结构,是指在运行时刻才能确定所需内存空间大小的数据结构,动态数据结构所使用的的内存称为动态内存。动态内存的使用有一定的危险,必须遵守一定的规则。动态申请的内存在不需要时必须及时释放,如果不断地申请动态内存而不加以释放,将导致内存资源的枯竭。

            c++处理动态内存提供了一对操作符new和delete。new操作符用于动态申请内存,而delete操作符则用来释放动态申请的内存。如果对象中为指针型属性申请了动态内存,则必须在析构函数中加以释放。

            在c++中,动态内存和指针变量是密切相关的,将指针变量和c++中的new和delete操作符结合起来,用来申请和释放动态内存。

            在程序运行过程中,当确定了数据所需内存空间的大小后,可以用new操作符请求系统分配足够的内存以存放该数据,并返回指向新申请到的内存区域的指针,如果申请不成功(这通常是因为内存空间不够),则返回空指针NULL。

            例如,下面的程序段中,new以数据类型T为参数,为类型为T的变量申请内存,返回得到内存地址。

            T*p;        //定义p为指向T的指针

            p=new T;//p为类型T数据的内存地址

             又如,当p1和p2分别为指向int和long类型数据的指针时,操作符new可以为它们分别申请相应的内存空间并将其他地址分别赋给p1和p2。

            int*p1;          //定义p1为指向int(2字节大小)的指针

            long*p2;       //定义p2为指向long(4字节大小)的指针

            p1=new int;  //p1指向内存中的一个整数

            p2=new long;//p2指向内存中的一个长整数

            默认情况下,new申请的内存中的内容没有初值,如果需要初值,必须使用操作符new的参数形式:

            p=new T(value);

             如下述操作:

            p1=new int(100);

            为整数申请内存并对其赋初值100,p1指向一个初值为100的整数。在c++中,不仅可以动态申请简单数据类型的内存空间,也可以申请复杂的数据类型,如动态数组的申请。程序中需要申请动态数组时,可用带方括号“[ ]”的new操作符为数组申请内存。例如:

            T*p;              定义p为指向T的指针

            p=new T[n];  为类型为T的n元数组申请内存

            将p指向数组的第一个元素。和简单数据类型不同,用这种方法申请数组时不能指定初始值。当申请的动态内存不再需要时,使用delete操作符加以释放。需要注意的是,delete的使用形式必须和new相匹配。例如:

            T*p1,*p2;       //p1和p2均为指向类型T的指针

            p1=new T;      //p1指向一个类型为T的数据

            p2=new T[n];  //p2指向一个类型为T的n元数组

            操作符delete使用这些指针来释放为它们申请的内存,但在释放数组时,必须与“[ ]”运算符结合使用:

            delete p1;//释放p1指向的简单变量空间

            delete [ ] p2; //释放p2指向的数组变量空间

    展开全文
  • AbstractRoutingDataSource动态数据源切换 上周末,室友通宵达旦的敲代码处理他的多数据源的问题,搞的非常的紧张,也和我聊了聊天,大概的了解了他的业务的需求。一般的情况下我们都是使用SSH或者SSM框架进行处理...
  • ECharts动态获取数据

    千次阅读 2017-09-28 10:35:25
    ECharts动态获取数据
  • C语言动态数据结构

    千次阅读 2016-12-23 20:59:37
    动态数据结构指的是 动态存储分配链表是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)静态链表:所有节点在程序中定义,而不是临时开辟...
  • java 写一个接口,利用json动态数据生成表格表头 求解
  • layui之动态数据表格

    万次阅读 2018-07-19 09:53:14
    layui数据动态表格,如果返回的json格式是默认格式就好了,从api上直接copy下来用就可以,可是我这里返回的json格式如下: { "code": 200, "content": { "currentPage": 1, &...
  • python中plot实现即时数据动态显示方法

    万次阅读 多人点赞 2017-02-28 22:25:04
    在Matlab使用Plot函数实现数据动态显示方法总结中介绍了两种实现即时数据动态显示的方法。考虑到使用python的人群日益增多,再加上本人最近想使用python动态显示即时的数据,网上方法很少,固总结于此。 示例代码...
  • 动态数据源切换

    千次阅读 2019-07-03 15:49:27
    目的:在Springboot中实现多数据源,并动态切换数据源,写数据用主数据库,查数据用从数据库,实现读写分离。 原理: 首先要将主、从数据库都加入自定义的数据源库DynamicRouterDataSource中(继承自springboot...
  • echarts 3 动态数据数据渲染

    万次阅读 2019-01-07 18:02:30
    app.title = '极坐标系下的堆叠柱状图'; option = { angleAxis: { type: 'category', data: ['周一', '周二', '周三', '周四', '周五', '周六', '...方法 进行数据的移除操作然后 push() 新的数据 效果图
  • JdbcTemplate动态数据源配置

    千次阅读 2019-09-04 22:44:24
    一、前言 多数据源的配置,是一个相对比较常见的需求。 什么是数据源?数据源就是javax.sql.DataSource,所有实现了这个接口的DataSource就叫做数据源,现在...而这些场景下的业务sql通常是属于动态数据源,它们的...
  • Vue使用swiper插件时特别是轮播元素含有动态数据时可能会出现数据为空或者白屏的问题 使用一下的方法可以解决(保证在数据请求之后再渲染页面) 页面结构 &amp;amp;amp;amp;amp;lt;div class=&amp;...
  • Echarts动态加载数据

    千次阅读 2017-05-05 21:38:02
    在为写这个项目之前,并没有大范围的写过前端,这次也是锻炼了,由于项目需求,要求echarts图动态加载数据(定时加载),一下是我在网上看到的例子,在此基础上做了修改,实现了功能。但觉得还有很多需改进和学习的...
  • 爬虫第五课:动态数据-拉勾网

    千次阅读 2019-01-10 19:13:28
    拉勾网动态数据爬取 网页的数据类型有两种,一种是动态数据,一种是静态数据。猫眼电影的数据就是静态数据,因为网页中所有的信息可以在它的源代码页中找到,像58同城,boss直聘里的数据都是静态生成的,可以很容易...
  • xtraReprot 动态绑定数据 数据动态

    千次阅读 2014-11-27 15:31:40
    这样做并不是我想出来的,是之前做一个报表模板时搜的,原地址忘了 ...灰色那个XRtable是显示列标题的,下面那个是显示绑定数据的 下面是报表页面代码: namespace OlenoUI.Report { public partial class
  • layui动态表格 动态查询数据

    千次阅读 2019-05-22 13:23:33
    layui动态表格 动态查询数据 首先定义一个文本框和一个搜索 注意搜索按钮里的 data-type=“reload” 和input id 搜索内容 ${articleTitleQuery.title}" placeholder="请输入搜索内容"> ...
  • 14、静态数据结构和动态数据结构

    千次阅读 2018-05-16 17:09:27
    动态数据结构,例如链表在内存中不是连续的存储区域,每一个节点包含节点数据和下一个节点的指针。缺点是不利于节点的随机访问。访问节点花费时间比较多,为O(n)。优点是能够动态的调整容量,插入或者删除数据方便。...
  • Spring动态切换多数据源Demo

    千次下载 热门讨论 2015-02-03 15:24:55
    请自行修改com/resources/datasource.properties中数据库配置,Demo中配置的两个数据源,一个是Mysql,一个是Oracle。 运行之前请自行建立数据库的表。
  • swiper支持动态加载数据

    万次阅读 2018-01-24 20:39:43
    用swiper插件动态加载数据动态获取完数据之后,在初始化swiper. 1、在标签里面加入swiper的css和js文件 2、html如下: 3、js如下: function handle
  • 一、AbstractRoutingDataSource Spring boot提供了...实现可动态路由的数据源,在每次数据库查询操作前执行。它的抽象方法 determineCurrentLookupKey() 决定使用哪个数据源。 org.springframework...
  • 最近在做一款游戏的GM管理平台,需要连接游戏的数据库去查询数据;由于游戏的每个服的数据是独立的,所以就有了连接多个数据库的问题;经过一番查找,好在mybatis的学习资源还少,很快找到了配置多数据源的方法;...
  • 分公司各自使用各自的业务数据库,用户登陆访问A数据库校验成功后将用户所属分公司的KEY保存session中(此文章以存放session为例,其他存放方式参考即可),当然本文重点在与还可以动态增加EFG。。。。分公司,无需...
  • hive使用动态分区插入数据详解

    万次阅读 多人点赞 2018-05-20 15:21:57
    往hive分区表中插入数据时,如果需要创建的分区很多,比如以表中某个字段进行分区存储,则需要复制粘贴修改很多sql去执行,效率低。因为hive是批处理系统,所以hive提供了一个动态分区功能,其可以基于查询参数的...
  • Element-UI的表格动态加载数据

    万次阅读 2017-08-16 16:59:08
    Element-UI的表格动态加载数据
  • Spring实现动态数据源切换

    万次阅读 2015-09-15 18:33:43
    如下流程是我在实现Spring数据动态切换到过程中遇到的问题接处理方式。   1、编写数据源切换的类 //此类时用于切换数据源时所调用的类及方法 public class DataSourceContextHolder { public static final ...
  • Matlab使用Plot函数实现数据动态显示方法总结

    万次阅读 多人点赞 2017-02-28 22:00:37
    由于静态画图的方法较多,本文只针对增量式数据流的动态显示。本文主要介绍几种Matlab实现数据动态显示方法。方法主要有两种:hold on set函数与drawnow函数组合 hold on 方法1. 方法介绍此种方法比较原始,...
  • ECharts3 实现动态数据累积图

    万次阅读 2017-09-21 18:46:27
    原来网站上的实例是固定只显示10个数据,简单做了一些修改,1秒生成1个数据,数据累积。可在ECharts3实例中的代码框中粘贴直接查看效果 ... text: '动态数据', subtext: '纯属虚构' }, tooltip: { trigger: '

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,172,078
精华内容 868,831
关键字:

属于动态数据的是