[{&quot 转译回来;id&quot 转译回来;:2},{&quot 转译回来;id&quot 转译回来;:3},{&quot 转译回来;id&quot 转译回来;:14}]如何2,3,14放一个集合里(数据动态)

再谈缓存的穿透、数据一致性和最终一致性问题再谈缓存的穿透、数据一致性和最终一致性问题井的另一面百家号缓存穿透问题缓存穿透是指查询一个根本不存在的数据,缓存和数据源都不会命中。出于容错的考虑,如果从数据层查不到数据则不写入缓存,即数据源返回值为 null 时,不缓存 null。缓存穿透问题可能会使后端数据源负载加大,由于很多后端数据源不具备高并发性,甚至可能造成后端数据源宕掉。AutoLoadCache 框架一方面使用“拿来主义”机制,减少回源请求并发数、降低数据源的负载,另一方面默认将 null 值使用 CacheWrapper“包装”后进行缓存。但为了避免数据不一致及不必要的内存占用,建议缩短缓存过期时间,并增加相关的主动删除缓存功能,如下面代码所示 (代码一):public interface UserMapper {/*** 根据用户 id 获取用户信息**/@Cache(expire = 1200, expireExpression="null == #retVal ? 120: 1200", key = "'user-byid-' + #args[0]")UserDO getUserById(Long userId);/*** 更新用户信息**/@CacheDelete({ @CacheDeleteKey(value = "'user-byid-' + #args[0].id") })void updateUser(UserDO user);}通过 expireExpression 动态设置缓存过期时间,上面例子中,getUserById 方法如果没有返回值,缓存时间为 120 秒,有数据时缓存时间为 1200 秒。调用 updateUser 方法时,删除"user-byid-{userId}"的缓存。还要记住一点,数据层出现异常时,不能捕获异常后直接返回 null 值,而是尽量把异常往外抛,让调用者知道到底发生了什么事情,以便于做相应的处理。数据一致性问题进行补充一些初学者使用 AutoloadCache 框架进行管理缓存时,以为在原有的代码中直接加上 @Cache、@CacheDelete 注解后,就完事了。其实并没这么简单,不管你有没有使用 AutoloadCache 框架,都需要考虑同一份数据是否会在多次缓存后,造成缓存无法更新的问题。尽量做到 允许修改的数据只被缓存一次,而不被多次缓存,保证数据更新时,缓存数据也能被同步更新,或者方便做主动清除,换句话说就是尽量缓存不可变数据。而如果数据更新频率足够低,那么在业务允许的情况下,则可以直接使用最终一致性方案。下面举个例子说明这个问题:业务背景:用户表中有 id, name, password, status 字段,name 字段是登录名。并且注册成功后,用户名不允许被修改。假设用户表中的数据,如下:下面是 Mybatis 操作用户表的 Mapper 类 (代码二):public interface UserMapper {/*** 根据用户 id 获取用户信息**/@Cache(expire = 1200, key = "'user-byid-' + #args[0]")UserDO getUserById(Long userId);/*** 根据用户名获取用户信息**/@Cache(expire = 1200, key = "'user-byname-' + #args[0]")UserDO getUserByName(String name);/*** 根据动态组合查询条件,获取用户列表**/@Cache(expire = 1200, key = "'user-list-' + #hash(#args[0])")List listByCondition(UserCondition condition);/*** 添加用户信息**/@CacheDelete({ @CacheDeleteKey(value = "'user-byname-' + #args[0].name") })void addUser(UserDO user);/*** 更新用户信息**/@CacheDelete({ @CacheDeleteKey(value = "'user-byid-' + #args[0].id") })void updateUser(UserDO user);/*** 根据用户 ID 删除用户记录**/@CacheDelete({ @CacheDeleteKey(value = "'user-byid-' + #args[0]") })void deleteUserById(Long id);}假设 alice 登录后马上进行修改密码,并重新登录验证新密码是否生效:1、alice 登录时,调用 getUserByName 方法,获取 User 数据,进行登录验证。这时会缓存数据:key 为:user-byname-alice;value 为:{"id":1, "name":"alice", "password":"123456", "status": 1}。2、此时又有人调 getUserById(1) 方法,会在缓存中增加数据,key 为:user-byid-1,value 为:{"id":1, "name":"alice", "password":"123456", "status": 1}。此时缓存中 user-byname-alice 和 user-byid-1 这两个缓存 key 对应的数据完全一样,即是同一数据,被缓存了多次。3、alice 修改登录密码 (调用 updateUser 方法),修改数据库中数据的同时删除 user-byid-1 的缓存数据,但是没有删除 user-byname-alice 的数据。4、alice 重新登录,想验证新密码是否生效时,验证不通过。问题已经清楚了,那该如何解决呢?我们都知道 ID 是数据的唯一标识,而且它是不允许修改的数据,不用担心被修改,所以可以对它重复缓存,那么就可以使用 id 作为中间数据。为了让大家更好地理解,将上面的代码进行重构 (代码三):public interface UserMapper {/*** 根据用户 id 获取用户信息* @param id* @return*/@Cache(expire=3600,expireExpression="null == #retVal ? 600: 3600",key="'user-byid-' + #args[0]")UserDO getUserById(Long id);/*** 根据用户名获取用户 id* @param name* @return*/@Cache(expire = 1200,expireExpression="null == #retVal ? 120: 1200",key = "'userid-byname-' + #args[0]")Long getUserIdByName(String name);/*** 根据动态组合查询条件,获取用户 id 列表* @param condition* @return**/@Cache(expire = 600, key = "'userid-list-' + #hash(#args[0])")List listIdsByCondition(UserCondition condition);/*** 添加用户信息* @param user*/@CacheDelete({@CacheDeleteKey(value = "'userid-byname-' + #args[0].name")})int addUser(UserDO user);/*** 更新用户信息* @param user* @return*/@CacheDelete({@CacheDeleteKey(value="'user-byid-' + #args[0].id", condition="#retVal > 0")})int updateUser(UserDO user);/*** 根据用户 id 删除用户记录**/@CacheDelete({@CacheDeleteKey(value = "'user-byid-' + #args[0]", condition="#retVal > 0")})int deleteUserById(Long id);}@Service@Transactional(readOnly=true)public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userM@Overridepublic UserDO getUserById(Long id) {return userMapper.getUserById(id);}@Overridepublic List listByCondition(UserCondition condition) {List list = new ArrayList();List ids = userMapper.listIdsByCondition(condition);if(null != ids && ids.size() > 0) {for(Long id : ids) {list.add(userMapper.getUserById(id));}}}@Override@CacheDeleteTransactional@Transactional(rollbackFor=Throwable.class)public void register(UserDO user) {Long userId = userMapper.getUserIdByName(user.getName());if(null != userId) {throw new RuntimeException("用户名已被占用");}userMapper.addUser(user);}@Overridepublic UserDO doLogin(String name, String password) {Long userId = userMapper.getUserIdByName(name);if(null == userId) {throw new RuntimeException("用户不存在!");}UserDO user = userMapper.getUserById(userId);if(null == user) {throw new RuntimeException("用户不存在!");}if(!user.getPassword().equals(password)) {throw new RuntimeException("密码不正确!");}}@Override@CacheDeleteTransactional@Transactional(rollbackFor=Throwable.class)public void updateUser(UserDO user) {userMapper.updateUser(user);}@Override@CacheDeleteTransactional@Transactional(rollbackFor=Throwable.class)public void deleteUserById(Long userId) {userMapper.deleteUserById(userId);}}通过上面代码可看出:1、缓存操作与业务逻辑解耦后,代码的维护也变得更加方便;2、只有 getUserById 方法的缓存是直接缓存用户数据,其它地方只缓存用户 ID。数据更新时,就不需要再关心其它数据也要同步更新的问题了,更好地保证了数据的一致性。细心的读者也许会问,如果系统中有一个查询 status = 1 的用户列表 (调用上面的 listIdsByCondition 方法),而这时把这个列表中的用户 status = 0,缓存中的并没有把相应的 id 排除,那么不就会造成业务不正确了吗?这个主要是要考虑系统可接受这种不正确情况存在多久。这时就需要前端加上相应的逻辑来处理这种情况。比如,电商系统中,某商口被下线了,可有些列表页因缓存没及时更新,仍然显示在列表中,但在进入商品详情页或者点击购买时,一定会有商品已下线的提示。通过上面例子我们发现,需要根据业务特点,思考不同场景下数据之间的关系,这样才能设计出好的缓存方案。有兴趣的读者可以思考一下,上面例子中,如果用户名允许修改的情况下,相应的代码要做哪些调整?如何保证数据最终一致?在数据更新时,如果出现缓存服务不可用的情况,造成无法删除缓存数据,当缓存服务恢复可用时,就可能出现缓存数据与数据库中的数据不一致的情况。为了解决此问题笔者提供以下几种方案:方案一,基于 MQ 的解决方案。如下图所示:流程如下:1、更新数据库数据;2、删除缓存中的数据,可此时缓存服务出现不可用情况,造成无法删除缓存数据;3、当删除缓存数据失败时,将需要删除缓存的 Key 发送到消息队列 (MQ) 中;4、应用自己消费需要删除缓存 Key 的消息;5、应用接收到消息后,删除缓存,如果删除缓存确认 MQ 消息被消费,如果删除缓存失败,则让消息重新入队列,进行多次尝试删除缓存操作。方案二,基于 Canal 的解决方案。如下图所示:流程如下:1、更新数据库数据;2、MySQL 将数据更新日志写入 binlog 中;3、Canal 订阅 & 消费 MySQL binlog,并提取出被更新数据的表名及 ID;4、调用应用删除缓存接口;5、删除缓存数据;6、Redis 不可用时,将更新数据的表名及 ID 发送到 MQ 中;7、应用接收到消息后,删除缓存,如果删除缓存确认 MQ 消息被消费,如果删除缓存失败,则让消息重新入队列,进行多次尝试删除缓存操作,直到缓存删除成功为止。像电商详情页这种高并发的场景,要尽量避免用户请求回源到数据库,所以会把数据都持久化到 Redis 中,那么相应的缓存架构也要做些调整。流程如下:1、更新数据库数据;2、MySQL 将数据更新日志写入 binlog 中;3、Canal 订阅 & 消费 MySQL binlog,并提取出被更新数据的表名及 ID;4、将更新数据的表名及 ID 发送到 MQ 中;5、应用订阅 & 消费数据更新消息;6、从数据库中拉取最新的数据;7、更新缓存数据,如果更新缓存失败,则让消息重新入队列,进行多次尝试更新缓存操作,直到缓存更新成功为止。此方案中,把数据更新的消息发送到 MQ 中,主要避免数据更新洪峰时,造成从数据库获取数据压力过大,起到削峰的作用。通过 Canal 就可以把最新数据发到 MQ 以及应用,为什么还要从数据库中获取最新数据?因为当消息过多时,MQ 消息可能出现积压,应用收到时可能已经是“旧”消息,通过去数据库取一次,以保证缓存数据是最新的。总的来说以上几种方案都借助 MQ 重复消费功能,以实现缓存数据最终得以更新。为了避免 MQ 消息积压,前两种方案都是先尝试直接删除缓存,当出现异常情况时,才使用 MQ 进行补偿处理。方案一实现比较简单,但如果 MQ 出现故障时,还是会造成一些数据不一致的情况,而方案二因为增加了删除缓存流程,延长了缓存数据的更新时间,但是可以弥补方案一中因 MQ 故障造成数据不一致的情况:Canal 可以重新订阅和消费 MQ 故障后的 binlog,从而增加了一重保障。 而第三种方案中 Redis 不仅仅是做缓存用了,还有持久化的功能在里面,所以采用更新缓存而不是删除缓存保证 Redis 的数据是最新的。本文由百家号作者上传并发布,百家号仅提供信息发布平台。文章仅代表作者个人观点,不代表百度立场。未经作者许可,不得转载。井的另一面百家号最近更新:简介:现在你已经伤害了过去,不要让它去作者最新文章相关文章ORA-00904:&T1&.&AREA_ID&:标识符无效
1、错误描述
ORA-00904:&T1&.&AREA_ID& :标识符无效
00904 . 00000 - &%s:invalid identifier&
行45列8出错
2、错误原因
在拼接SQL语句时,未查询“AREA_ID”,并且group by中没有“AREA_ID”
3、解决办法
在拼接SQL语句时,select中加上AREA_ID,group by AREA_ID||百姓网公众号微信扫码关注百姓网小程序微信扫扫立即体验扫码下载手机客户端免费抢油卡、红包、电影票您正在浏览信息,点击查看更多服务首付一万
重点学区房
送精装修&价格:24.2万元房型:1室1厅1卫面积:41.1平米小区名:山伟学府花园地址:&-&&威海文登市中心联系:(大连)联系时,请一定说明在百姓网看到的,谢谢!见面最安全,发现问题请举报其他联系:具体地点:威海文登市中心javascript:id_post_form.t&&itle.value=&快快着手,首付一万送精装修啦!不要再等待!!!&;id_post_form.xiaoqu.value=&山伟学府花园&;javascript:for (var i = 0; i & id_post_form.district_id.options. i++) { if (id_post_form.district_id.options[i].text == &延寿&) { id_post_form.district_id.options...javascript:id_post_form.t&&itle.value=&快快着手,首付一万送精装修啦!不要再等待!!!&;id_post_form.xiaoqu.value=&山伟学府花园&;javascript:for (var i = 0; i & id_post_form.district_id.options. i++) { if (id_post_form.district_id.options[i].text == &延寿&) { id_post_form.district_id.options[i].selected = }}id_post_form.xiaoqu_address.value=&山东省威海文登市中心&;id_post_form.huxing_shi.value=&1&;id_post_form.huxing_ting.value=&1&;id_post_form.huxing_wei.value=&1&;id_post_form.ceng.value=&20&;id_post_form.ceng_total.value=&30&;id_post_form._unused[0].value=&南北&;id_post_form.chaoxiang.value=&6&;id_post_form._unused[1].value=&普通住宅&;id_post_form.fang_xing.value=&3&;id_post_form._unused[2].value=&精装修&;id_post_form.zhuangxiu.value=&2&;id_post_form.area.value=&41.1&;id_post_form.price.value=&24.2&;id_post_form.description.value=&书香气息典雅之所 彰显您的尊贵身份 可加QQ:空间有详细资料 2013年中国十佳宜居城市出炉,威海排名全国第一特大喜讯:山伟学府花园----文登新人居典范,精装修小户型不限购可贷款可落户,首付1万元,送精装修,面积区间35.5平--67.8平,楼层任选;而且最重要的是目前小区东边的省重点高中的老师已经团购本项目了,而且最小的户型能租到1300元/月的,而且贷款20年月还仅需要1265元/月,以房养房,这么好的项目哪找去,也就是山伟学府花园吧! 现面向全国接受预定新盘预售中!!!内部认购价5888元,一楼到30楼统一价格,开盘价格会有楼层差价!最低差价30元。例如:买个20层的楼房,现在5888元/平
50㎡ :等到开盘 每层差价最低30元
20层*30元=600元(差价) 600*50㎡=30000元(短短的一个月的时间内,就能升值2-3万元,也就是说零首付买一套房子。)升值空间无限大!!!!赶快抢购吧!!!此房源在文登新城区中心地段,近邻文登新一中,绝对是黄金地段,就是好,要知道详细内容马上打电话:136
成功者总能先比别人看到机会,在最有利的实际投资最有升值潜力的物业。小贴士:本页信息由用户及第三方发布,真实性、合法性由发布人负责。详情请阅读
1/8显示照片列表信息设置为“搞定了!”状态后,其他用户将无法查看您的联系方式。您确认搞定了这条信息吗?重新发布后可使用“刷新”将发布时间更新为最新时间,并将信息排到第一页。商户推广合作加盟服务支持合作伙伴|&| 沪公网安备16号11&G:86&GM:92
描述:请填写描述手机号:请填写手机号请填写手机号上传图片:打开微信,扫一扫右侧二维码,即可完成绑定 -->绑定后,您可以:1. 立即在手机上收到用户给您的留言2. 使用手机快速完成付费推广的续费动作3. 第一时间了解到百姓网付费推广最新的促销活动,以及享受微信端独特的促销活动4. 更快速地将信息通过微信分享给好友、同事、朋友圈5. 如果您是招聘类目用户,还能够第一时间接收到新简历通知下载APP无需登录实时接受私信提醒,联系更便捷!或点击下方先登录再进入私信联系&nbsp>&nbsp
&nbsp>&nbsp
&nbsp>&nbsp
@+id/android:list&和&@android:id/list&的写法
摘要:Android中的列表,当然也可以用ListView来完成所需要的功能,用法是一样的。废话不说,来关键的。LiveActivity本身继承了关于List操作的众多接口,我们可以方便的重写这些操作中需要的方法来实现自己需要的功能。如果要用ListActivity,则Activity的Layout文件中必须包括一个(只能一个)ListView,且ListView的id=&@id/android:list&。如下代码,一个标准的ListActivityLayou
Android中的列表,当然也可以用ListView来完成所需要的功能,用法是一样的。
废话不说,来关键的。
LiveActivity本身继承了关于List操作的众多接口,我们可以方便的重写这些操作中需要的方法来实现自己需要的功能。
如果要用ListActivity,则Activity的Layout文件中必须包括一个(只能一个)ListView,且ListView的id=&@id/android:list&。
如下代码,一个标准的ListActivity Layout文件:
&?xml version=&1.0&encoding=&utf-8&?&
<linearlayoutxmlns:android="http: schemas.android.com="" pk="" es="" ndroid"
android:orientation=&vertical&
android:layout_width=&fill_parent&
android:layout_height=&fill_parent&
android:paddingLeft=&8dp&
android:paddingRight=&8dp&&
<listviewandroid:id="@id ndroid:list"
android:layout_width=&fill_parent&
android:layout_height=&fill_parent&
android:background=&#00FF00&
android:layout_weight=&1&
android:drawSelectorOnTop=&false&/&
<textviewid="@id ndroid:empty"
android:layout_width=&fill_parent&
android:layout_height=&fill_parent&
android:background=&#FF0000&
android:text=&No data&/&
请注意 ListView与TextView的id。前面说了,
1. ListView的Id为固定不变的,为&@id/android:list“,ListActivity会根据id自动查找ListView引用;在 Activity 中使用 setListAdapter(adapter); 时就默认设置到了这个list上。如果按一般控件的写法
,则需要 findViewById 先得到控件对像,再调用对像的 setListAdapter(adapter);
2. 但如果当ListView中没有值而又想提示一句话时,那么用于指定显示提示信息的TextView的id必须为”&@id/android:empty&,提示的信息可以通过android:text进行指定。
在实际中,也可以这样写,如Android2.3中的call_detail.xml中:
<listview android:id="@android:id/list"
android:layout_width=&match_parent&
android:layout_height=&match_parent&
android:scrollbarStyle=&outsideOverlay&
<scrollview android:id="@android:id/empty"
android:layout_width=&match_parent&
android:layout_height=&match_parent&
android:fillViewport=&true&&
<textview android:id="@+id/emptyText"
android:layout_width=&match_parent&
android:layout_height=&wrap_content&
android:text=&@string/unknown&
android:textSize=&20sp&
android:textColor=&?android:attr/textColorSecondary&
android:paddingLeft=&10dip&
android:paddingRight=&10dip&
android:paddingTop=&10dip&
android:gravity=&center&
android:lineSpacingMultiplier=&0.92&/&
这个写法更加实用了,可以通过在listview没有显示数据时可以用@+id/emptyText进行动态赋值,而不用像前一个例子中的将empty text固化到xml中。
OK,关于如何布局说完了,那么如何给List绑定值,并进行操作呢?
首先我们需要确实的是,ListView的布局也完成了,并通过调用setContentView(…)进行了绑定,但直到现在我们还没有确定ListView中的第一行显示的格式是什么,是直接显示文字还是要“图文并茂”的显示。
Android系统为我们提供了多种模板进行选择(android.R.layout),如
&OSimple_list_item_1每项有一个TextView
&OSimple_list_item_2每项有两个TextView
&OSimple_list_item_checked带CheckView的项
&OSimple_list_item_multiple_choise每项有一个TextView并可以多选
&OSimple_list_item_single_choice每项有一个TextView,但只能进行单选。
但然,如果以上项模板还无法满足你的要求,那只能自定义模板了(相当简单,就是定义一个layout布局)。如果你做的asp.net的开发的话,是否对dataList控件有印象呢。如果对DataList有印象,那么理解ListView也就相当的简单了。
自定义模板可以根据自己的需要定义成任意的格式,包括图片、方案及其他可显示的View,不用多说,自己定义就好了,关键是如果使用并进行模板的绑定。
如何要对ListView进行数据绑定,必须使用到一个接口:Adapter。
其中最经常与ListView进行配合使用的有ArrayAdapter、CursorAdapter及SimpleAdapter等。
从名称可以看出ArrayAdapter使用的是一个ArrayAdapter做为数据源,SimpleCursorAdapter使用的是一个Cursor使用数据源,都比较容易理解,那么如何使用SimpleAdapter作为数据的适配器呢。Ok,从易到难。
ArrayAdapter:
String[] data = { &Item1&, &Item2&,
&Item3&, &Item4&, &Item5& };
listView.setAdapter(new ArrayAdapter
android.R.layout.simple_list_item_single_choice, data));
SimpleCursorAdapter:
//从数据库中查询Cursor
cursor = adapter.getAllNotes();
startManagingCursor(cursor);
//设置要显示的数据源中的列名(需要包含在cursor中)
String[] from = new String[] { DiaryDbAdapter.KEY_COLUMN_TITLE,
DiaryDbAdapter.KEY_COLUMN_CREATEED };
//显示的View(自定义模板中的View)
int[] to = new int[] { R.id.txtRowTitle, R.id.txtRowCreateed };
SimpleCursorAdapter notes = new SimpleCursorAdapter(this,
R.layout.diaryrow, cursor, from, to);
setListAdapter(notes);、
SimpleAdapter:
SimpleAdapter将一个List做为数据源,可以让ListView进行更加个性化的显示。而List中的第一项是个Map
(用到泛型),其中Map中的每项将与ListView中的每项进行一一对应绑定。Ok,看一下构造:
SimpleAdapter(Context context,List&? Extends Map
& data,int resource,String [] form, int [] to);
&sup2;Context:当前上下文,一般把Activity.this传递进行。
&sup2;Data:数据源。
&sup2;Resource:自定义的layout模板资源,可以用R.layout.xxx获取引用。
&sup2;Form:定义ListView中的每一项数据索引,索引来自于Map
,即指定要显示的内容。
&sup2;To:View数组,在ListView模板中的定义View,与Form中需要一一对应。
<hashtable
& listContent
</hashtable
=newArrayList
<hashtable
</hashtable
for(inti = 0; i &deviceList.size(); i++) {
=newHashtable
table.put(&name&,deviceList.get(i).Name);
table.put(&address&,deviceList.get(i).Address);
table.put(&type&,deviceList.get(i).Type+&&);
listContent.add(table);
adapter=newSimpleAdapter(HeartActivity.this,
listContent, R.layout.child, //自定义的layout
newString[] {&name&,&address&},
newint[] {R.id.txtDeviceName, R.id.txtDeviceAddress});
setListAdapter(adapter);
以上代码使用了Hashtable做为一个Map,并添加到一个List
<hashtable
</hashtable
之后new一个SimpleAdapter,注意SimpleAdapter是如何生成的。
以上是的内容,更多
的内容,请您使用右上方搜索功能获取相关信息。
若你要投稿、删除文章请联系邮箱:zixun-group@service.aliyun.com,工作人员会在五个工作日内给你回复。
云服务器 ECS
可弹性伸缩、安全稳定、简单易用
&40.8元/月起
预测未发生的攻击
&24元/月起
邮箱低至5折
推荐购买再奖现金,最高25%
&200元/3月起
你可能还喜欢
你可能感兴趣
阿里云教程中心为您免费提供
@+id/android:list&和&@android:id/list&的写法相关信息,包括
的信息,所有@+id/android:list&和&@android:id/list&的写法相关内容均不代表阿里云的意见!投稿删除文章请联系邮箱:zixun-group@service.aliyun.com,工作人员会在五个工作日内答复
售前咨询热线
支持与服务
资源和社区
关注阿里云
International{&error_code&:31064,&error_msg&:&expire time out error&,&request_id&:}
来源:网络
作者:福州电脑之家
网友求助:{&error_code&:31064,&error_msg&:&expire time out error&,&request_id&:}
应该是有驱动没装好,重新安装驱动试试
暂无其它答案...
友情链接:
福州电脑网(福州iThome)专业电脑/计算机学习网站.提供电脑维修知识,包括计算机软件/硬件维修知识,路由器/交换机/网络设置,电脑蓝屏,网络/it知识学习等等电脑技术学习资料.
免责声明:本站所有信息内容仅供参考,如有冒犯您的权益请联系我们删除!请大家注意:本站删帖完全免费。邮箱:
Copyright (C) , All Rights Reserved.
版权所有 闽ICP备号-3}

我要回帖

更多关于 quot 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信