`
marb
  • 浏览: 425902 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

JAVA事务四

 
阅读更多

Java中, 对于事务模式, 一般总结为三种。 本地事务, 编程式事务和声明事务。 下面, 我们就分别谈谈这三种事务模式。
      
     事务的ACDI 
事务有atomicity, consistancy, isolation and durability.

原子性, 事务在一个单元操作中, 要么提交, 要么回滚。有时候, 我们把它叫做LUW(logic unit of work)或者 SUW(single unit of work).

一致性, 事务在原子操作中, 永远不会处于非一致性的状态。 即在每次的原子事务中的insert, update, or delete, 都会拥有一致性的检查, 尽管事务还没有提交。

隔离性, 它表示不同的事务之间互相作用的程度。 ACDI属性, 决定了怎样保护我更新的那些资源, 而这些资源其它的事务也可以访问。 随着隔离性的提高, 一致性增强了而并发性减弱了。

持久性, 就是提交到数据库, 或者JMS更新到server的数据, 都会持久保存下来。

JTA and JTS

Java 开发中, 有效的管理事务, 并不需要知道 JTA(java transaction service)的后台处理。 但是, 理解java中分布式事务的限制是很重要的。

不管你用什么框架, 很多的企业应用, 都借助JTA(java transaction API)管理事务. JTA是开发者管理事务的接口。 JTS呢, 就是JTA下面的服务, 就像是JDBC和数据库driver之间的关系。  JTA的实现, 可以是商用服务器, 也可以使开源的服务器 (jboss)。 因为JTA必须支持JTS和非JTS实现,

UserTransaction Interface 
这个接口, 只在编程式事务中使用, 一般关注它的四个方法:

  • begin()
  • commit()
  • rollback()
  • getStatus()


这几个方法干嘛的。 就不用说了。

TranscationManager Interface
它主要用于声明式事务中, 在编程事务中, 我们也可以用它做UserTranscation的动作。 但最好在需要使用suspend和resume时, 用TransactionManager.

javax.transaction.TransactionManager.suspend()
在申明式或编程事务中, 把当前线程相关的事务suspend。 这个方法返回当前事务或者null.

javax.transaction.TransactionManager.resume()
它用于恢复上面暂停的事务。

Status Interface
方法UserTransaction.getStatus()可以获得 Status Interface。 它可以从当前事务中获得很多的信息。 它有下面的一些 value:

  • STATUS_ACTIVE
  • STATUS_COMMITTED
  • STATUS_COMMITTING
  • STATUS_MARKED_ROLLBACK
  • STATUS_NO_TRANSACTION
  • STATUS_PREPARED
  • STATUS_PREPARING
  • STATUS_ROLLEDBACK
  • STATUS_ROLLING_BACK
  • STATUS_UNKNOWN



对于开发人员来说, 特别重要的是STATUS_ACTIVE , STATUS_MARKED_ROLLBACK和STATUS_NO_TRANSACTION。  下面会更加详细的介绍他们。

STATUS_ACTIVE
很多时候, 需要检查当前线程是否绑定了事务, 来进行进一步的查询或处理。 例如:

Java代码  收藏代码
  1. ...  
  2. if  (txn.getStatus() == Status.STATUS_ACTIVE)  
  3. logger.info("Transaction active in query operation" );  
  4. ...  



STATUS_MARKED_ROLLBACK
在申明事务中, 这个状态很有用。 为了性能的考虑, 我们也许需要跳过一些处理, 如果事务被前面的方法回滚后。

Java代码  收藏代码
  1. ...  
  2. if  (txn.getStatus() == Status.STATUS_MARKED_ROLLBACK)  
  3. throw   new  Exception(  
  4. "Further Processing Halted Due To Txn Rollback" );  
  5. ...  



STATUS_NO_TRANSACTION
这是唯一的一个方法确定上下文中没有事务。

Java代码  收藏代码
  1. ...  
  2. if  (txn.getStatus() == Status.STATUS_NO_TRANSACTION)  
  3. throw   new  Exception(  
  4. "Transaction needed but none exists" );  
  5. ...  


我们不能用STATUS_ACTIVE去判断是否没有事务。 事务还可能是其他的状态。

本地事务
本地事务, 其实就是DBMS或者JMS提供的事务管理。对于开发人员, 在本地事务中, 我们不用管理transactions, 而是 connections. 下面的代码说明了这个问题:

Java代码  收藏代码
  1. public   void  updateTradeOrder(TradeOrderData order)  
  2. throws  Exception {  
  3. DataSource ds = (DataSource)  
  4. (new  InitialContext()).lookup( "jdbc/MasterDS" );  
  5. Connection conn = ds.getConnection();  
  6. conn.setAutoCommit(false );  
  7. Statement stmt = conn.createStatement();  
  8. String sql = "update trade_order ... " ;  
  9. try  {  
  10. stmt.executeUpdate(sql);  
  11. conn.commit();  
  12. catch  (Exception e) {  
  13. conn.rollback();  
  14. throw  e;  
  15. finally  {  
  16. stmt.close();  
  17. conn.close();  
  18. }  
  19. }  



在上面的例子中, 我们使用connection的提交, 回滚。 那个自动提交开关, 告诉DBMS是否在执行每条SQL后立刻提交。 这个开关, 默认是true.

在spring 框架中, 用底层的JDBC的话,可以使用org.springframework.jdbc.datasource.DataSourceUtils. 例如:

Java代码  收藏代码
  1. public   void  updateTradeOrder(TradeOrderData order)  
  2. throws  Exception {  
  3. Connection conn = DataSourceUtils  
  4. .getConnection(dataSource);  
  5. conn.setAutoCommit(false );  
  6. Statement stmt = conn.createStatement();  
  7. String sql = "update trade_order ... " ;  
  8. try  {  
  9. stmt.executeUpdate(sql);  
  10. conn.commit();  
  11. catch  (Exception e) {  
  12. conn.rollback();  
  13. throw  e;  
  14. finally  {  
  15. stmt.close();  
  16. conn.close();  
  17. }  
  18. }  



在spring 中, datasource 及相关的类, 可以在配置文件中定义为:

Java代码  收藏代码
  1. <bean id= "datasource"   
  2. class = "org.springframework.jndi.JndiObjectFactoryBean" >  
  3. <property name="jndiName"  value= "jdbc/MasterDS" />  
  4. </bean>  
  5. <bean id="TradingService"   
  6. class = "com.trading.server.TradingService" >  
  7. <property name="dataSource" >  
  8. <ref local="datasource" />  
  9. </property>  
  10. </bean>  




Auto Commit and Connection Management
自动提交, 在本地事务中是很重要的。 通过collection 传递,还是可以处理复杂点的逻辑的, 例如:

Java代码  收藏代码
  1. public   void  updateTradeOrder(TradeOrderData order)  
  2. throws  Exception {  
  3. DataSource ds = (DataSource)  
  4. (new  InitialContext()).lookup( "jdbc/MasterDS" );  
  5. Connection conn = ds.getConnection();  
  6. conn.setAutoCommit(false );  
  7. OrderDAO orderDao = new  OrderDAO();  
  8. TradeDAO tradeDao = new  TradeDAO();  
  9. try  {  
  10. //SQL and Connection Logic in DAO Classes   
  11. orderDao.update(order, conn);  
  12. tradeDao.update(order, conn);  
  13. conn.commit();  
  14. catch  (Exception e) {  
  15. logger.fatal(e);  
  16. conn.rollback();  
  17. throw  e;  
  18. finally  {  
  19. conn.close();  
  20. }  
  21. }  




这种方式, 在大多数情况下是可以工作的, 但这不是一个好的事务策略, 它需要大量的代码维护, 如果你需要类似上面的代码逻辑的话, 那你就应该使用编程事务或者申明事务了。

本地事务的考虑和限制
本地事务, 只能处理简单的逻辑, 如果系统需要复杂的处理, 对于应用架构, 这个模式会有一些危险的限制。

第一个地方, 就是在coding时候, 开发人员在很多地方容易犯错。开发人员需要时刻注意关掉自动提交功能。 在次, 如果许多方法有管理连接, 我们在调用这些方法的时候, 也要格外小心。 除非我们的应用基本上都是单表操作。 否则, 没有办法保证所以的SQL都在同一个事务中。

还有一个问题, 在使用XA global transaction时候, 本地事务不能存在并发。 当协调多个资源时候, 比如数据库和JMS destination的时候, 我们不能使用本地事务和确保ACDI属性。

基于上面的限制, 本地事务只能在简单的应用和单表操作中使用。

编程事务模型
编程事务于本地事务的最大不同, 就是开发者管理 transactions, 而不是 connections. 下面是个EJB中使用的场景:

Java代码  收藏代码
  1. public   void  updateTradeOrder(TradeOrderData order)  
  2. throws  Exception {  
  3. UserTransaction txn = sessionCtx.getUserTransaction();  
  4. txn.begin();  
  5. try  {  
  6. TradeOrderDAO dao = new  TradeOrderDAO();  
  7. dao.updateTradeOrder(order);  
  8. txn.commit();  
  9. catch  (Exception e) {  
  10. log.fatal(e);  
  11. txn.rollback();  
  12. throw  e;  
  13. }  
  14. }  



从上面的代码我们可以看到, 事务被传播到TradeOrderDAO对象中, 但不同于本地模型, TradeOrderDAO不再需要管理transcations 或者 connections. 它所需要做的, 就是从连接池中拿出连接并释放。

在编程事务中, 开发者需要开启和终于一个事务。 在EJB中, 这个通过UserTransaction接口实现, 在spring 中, 通过TransactionTemplate或者PlatformTransactionManager实现。

然后, 调用begin(), commit() 或者rollback()方法。

尽管编程事务模型常常不被鼓励使用, 但在一些场合下, 它确实挺有用的。下面的例子是在spring中使用情形:

Java代码  收藏代码
  1. public   void  updateTradeOrder(TradeOrderData order)  
  2. throws  Exception {  
  3. transactionTemplate.execute(new  TransactionCallback()  
  4. {  
  5. public  Object doInTransaction(  
  6. TransactionStatus status)  
  7. {  
  8. try  {  
  9. TradeOrderDAO dao = new  TradeOrderDAO();  
  10. dao.updateTradeOrder(order);  
  11. catch  (Exception e) {  
  12. status.setRollbackOnly();  
  13. throw  e;  
  14. }  
  15. }  
  16. } );  
  17. }  
  18. <bean id="transactionTemplate"   
  19. class ="org.springframework.transaction.support.  
  20. TransactionTemplate">  
  21. <property name="transactionManager" >  
  22. <ref local="transactionManager" />  
  23. </property>  
  24. </bean>  
  25. <bean id="tradingService"   
  26. class = "com.trading.server.TradingService" >  
  27. <property name="transactionTemplate" >  
  28. <ref local="transactionTemplate" />  
  29. </property>  
  30. </bean>  



从上面的例子看出, 使用框架, 并不需要调用begin(), commit()方法。

Obtaining a Reference to the JTA UserTransaction

在基于web应用中, 需要使用JNDI查找获得。例如:

Java代码  收藏代码
  1. ...  
  2. InitialContext ctx = new  InitialContext()  
  3. UserTransaction txn = (UserTransaction)  
  4. ctx.lookup("javax.transaction.UserTransaction" )  
  5. ...  



说到这, 这情况变得有点复杂了。 我们知道, 上面的事务通过jndiI绑定到服务器上。 有写服务器在外部不能获得JNDI resouce ( web container. like tomcat). 但有些是可以的(Jboss). 下面的列出一些常见的绑定的transaction.

JBoss: "UserTransaction"
WebLogic: "javax.transaction.UserTransaction"
WebSphere v5+: "java:comp/UserTransaction"
WebSphere v4: "jta/usertransaction"
SunONE: "java:comp/UserTransaction"
JRun4: "java:comp/UserTransaction"
Resin: "java:comp/UserTransaction"
Orion: "java:comp/UserTransaction"
JOnAS: "java:comp/UserTransaction"


上面的UserTransaction, 在容器外,往往不能获得,但在单元测试或者基于Swing的应用中, 我们怎么解决这个问题呢。 这时候, 我们需要通过Class.forName()方法加载服务端指定的TransactionManagerFactory类, 这样, 才能启动和停止一个事务。 下面的代码演示使用IBM Websphere TransactionManagerFactory:

Java代码  收藏代码
  1. ...  
  2. //load the transaction manager factory class   
  3. Class txnClass = Class.forName(  
  4. "com.ibm.ejs.jts.jta.TransactionManagerFactory" );  
  5. //using reflection invoke the getTransactionManager()   
  6. //method to get a reference to the transaction manager   
  7. TransactionManager txnMgr = (TransactionManager)  
  8. txnClass.getMethod("getTransactionManager" , null )  
  9. .invoke(null null );  
  10. //start the transaction via the transaction manager   
  11. txnMgr.begin();  
  12. ...  



我们可以用任何服务器的TransactionManagerFactory类替换掉上面的object. 这样我们可以在容器外拿到事务管理实例了。

在编程事务中,我们要特别注意异常处理。 看看下面的代码, 我们只处理checked 异常:

Java代码  收藏代码
  1. public   void  updateTradeOrder(TradeOrderData order)  
  2. throws  Exception {  
  3. UserTransaction txn = sessionCtx.getUserTransaction();  
  4. txn.begin();  
  5. try  {  
  6. TradeOrderDAO dao = new  TradeOrderDAO();  
  7. dao.updateTradeOrder(order);  
  8. txn.commit();  
  9. catch  (ApplicationException e) {  
  10. log.fatal(e);  
  11. txn.rollback();  
  12. throw  e;  
  13. }  
  14. }  



编程事务, 说明开发者要自己处理异常。特别注意且确保要关掉事务 (这在大大复杂项目中, 是件很难的事情:)。

编程事务使用场景
一般, 不鼓励使用编程事务, 但在一些场合中, 编程事务还是很有用的。 特别是事务是客户端发起的。 客户端需要调用多个 EJBbean时候,这是就需要在客户端使用它。 但要注意, ejb端需要使用申明事务, 因为编程事务不能在不同的bean之间传递。

另外一个场景就是, 因为JTA事务是比较耗资源的, 为了性能的需求, 我们需要在一些地方关掉事务, 比如银行系统。 只在转账的时候打开事务, 在加载, 验证数据的时 候关掉事务。 而这个在申明事务中很难做到, 因为申明事务没有编程控制, 不知道什么时候事务开始和结束。 

编程事务, 只有在你有好的理由需要使用的时候才使用它。 否则的话, 你就要用到申明事务。

申明事务模型
经过前面的介绍, 我们知道, 编程事务需要开发人员启动, 提交和回滚事务。 那么, 申明事务,容器管理着事务, 就不需要开发人员写Java代码去启动, 提交一个事务了。但是, 开发人员必须告诉容器, 怎样管理事务 。 在spring 中, 通过ApplicationContext.xml bean配置文件实现。

在Spring中, 我们通过TransactionProxyFactoryBean代理使用申明事务。 例如:

Java代码  收藏代码
  1. <bean id= "tradingServiceTarget"   
  2. class = "com.trading.server.TradingServiceBean" >  
  3. ...  
  4. </bean>  
  5. <bean id="tradingService"   
  6. [b]class ="org.springframework.transaction.interceptor.  
  7. TransactionProxyFactoryBean"[/b]>  
  8. <property name="transactionManager"  ref= "txnMgr" />  
  9. <property name="target"  ref= "tradingServiceTarget" />  
  10. <property name="transactionAttributes" >  
  11. <props>  
  12. <prop key="*" >PROPAGATION_SUPPORTS</prop>  
  13. <prop key="update*" >  
  14. PROPAGATION_REQUIRED,[b]-Exception[/b]  
  15. </prop>  
  16. </props>  
  17. </property>  
  18. </bean>  



配置文件中的-Exception, 表示遇到任何Exception都会回滚。 一般我们会指定一个特定的checked异常。

Transaction Attributes

容器, 通过Transaction Attributes, 知道怎样管理JTA事务。 一共有六个属性设置。 前面是EJB, 后面是Spring。

  • Required        PROPAGATION_REQUIRED
  • Mandatory     PROPAGATION_MANDATORY
  • RequiresNew  PROPAGATION_REQUIRES_NEW
  • Supports        PROPAGATION_SUPPORTS
  • NotSupported PROPAGATION_NOT_SUPPORTED
  • Never              PROPAGATION_NEVER
  •                         PROPAGATION_NESTED (only spring. not EJB)



要是使用PROPAGATION_NESTED, 后台的JTS必须能够支持事务的嵌套。

REQUIRED
必须使用, 上下文中没有的话, 需要创建一个新的事务。

MANDATORY
它表示需要一个事务, 但不像REQUIRED, 它不会创建一个新的事务。 如果上下文中没有事务, 就会抛出TransactionRequiredException。 表示需要的事务不存在。

REQUIRESNEW
它表示需要一个新的事务, 如果上下文中已经有了事务。 前面的事务就会挂起。 但这个新的事务终止的时候, 前面的事务会resumed。 这个特性违反ACDI属性 (如果前面存在事务时候)。 如果一个操对于外面的事务, 需要独自先完成时, 它是很有用的。比如, 记录log. 这个log会把前面的操作记录下来, 无论这前面的操作是成功或者失败。 如果不用这个特性, 记录log的操作, 在前面逻辑操作失败的情况下跟着回滚。 这就不符合任何操作都需要记录的理念了。

SUPPORTS
表示可以不需要事务, 但上下文中如果存在的话, 会使用前面的事务。

NOTSUPPORTED
这个表示不使用事务。 如果前面存在事务, 事务会被挂起然后等待这方法完成。这个常在那些方法可能会有异常的地方使用。

NEVER
跟notsupported不同, 如果前面有事务的话, 会抛出异常。
这个属性, 会导致不可预知或runtime exception. 所以慎重使用。

在Spring中,我们可以使用TransactionAttributeSource或者TransactionProxyFactoryBean. 下面分别演示这两种方法:

使用  TransactionAttributeSource

Java代码  收藏代码
  1. <bean id= "transactionAttributeSource"   
  2. class ="org.springframework.transaction.interceptor.  
  3. NameMatchTransactionAttributeSource">  
  4. <property name="properties" >  
  5. <props>  
  6. <prop key="*" >PROPAGATION_MANDATORY</prop>  
  7. </props>  
  8. </property>  
  9. </bean>  
  10. <bean id="tradingService"   
  11. class ="org.springframework.transaction.interceptor.  
  12. TransactionProxyFactoryBean">  
  13. <property name="transactionAttributeSource" >  
  14. <ref local="transactionAttributeSource" >  
  15. </property>  
  16. ...  
  17. </bean>  



使用 TransactionProxyFactoryBean

Java代码  收藏代码
  1. <bean id= "tradingService"   
  2. class ="org.springframework.transaction.interceptor.  
  3. TransactionProxyFactoryBean">  
  4. <property name="transactionManager"  ref= "txnMgr" />  
  5. <property name="target"  ref= "tradingServiceTarget" />  
  6. <property name="transactionAttributes" >  
  7. <props>  
  8. <prop key="*" >PROPAGATION_MANDATORY</prop>  
  9. </props>  
  10. </property>  
  11. </bean>  



对事务的属性, 一个相关的问题就是,在方法上指定属性, 而不是在类上。但一个好的方法应该是在类上定义属性, 对个别方法进行调整。  也是类上定义的, 是大多数方法都试用的。

例如 :

Java代码  收藏代码
  1. <bean id= "tradingService"  ...>  
  2. ...  
  3. <property name="transactionAttributes" >  
  4. <props>  
  5. [b]<prop key="*" >PROPAGATION_MANDATORY</prop>  
  6. <prop key="getAllTradersByID" >  
  7. PROPAGATION_SUPPORTS  
  8. </prop>[/b]  
  9. </props>  
  10. </property>  
  11. </bean>  




Required vs. Mandatory
有些情况下, 不知道这两种属性使用哪一种。 这里给出个最佳实践:
如果一个方法,并不负责回滚, 那么这个方法就使用Mandatory

怎么理解呢, 用反推法。 这是因为遵循一个原子, 事务是哪里启动的, 就跟在哪里回滚。 如果这个方法使用了Required。就会创建一个新的事务。 就永远不会回滚了。

事务隔离级别

对开发人员来说, 另外一个对事务的设定,就是隔离级别。 这个属性的设定, 依赖于服务器和数据库。服务器也许支持许多的隔离级别设定, 但数据库必须也要支持才能起效。  它的设定, 需要在一致性与并发性之间取个折中或者看业务需求。 这里介绍EJB和Spring支持的四种隔离级别。

  •   TransactionReadUncommitted
  •   TransactionReadCommitted  
  •   TransactionRepeatableRead
  •   TransactionSerializable 



TransactionReadUncommitted
这是最低的一个级别, 它允许事务读取另外事务中未提交的更新数据。 这个违反基本的ACID, 许多数据库厂商都不支持(包括Oracle)。

TransactionReadCommitted
这个级别, 允许多个事务访问同一个数据。 但是他们之间的更新, 只有在提交后才能读取。 这个级别, 是默认的设置且大多数厂商都支持的。

TransactionRepeatableRead
可重复读, 既多个事务, 每次查询的结果都是一样的 (自己更改的不算,因为自己拥有读, 写锁)。 例如, 有两个事务, 有一个事务更改了 数据并提交了。 另外一个事务, 在自己没有提交钱, 看到的仍然是自己开始取得的那个数据。 直到自己把事务提交后, 才知道林另外一个事务更改了数 据。

TransactionSerializable
这个是最高的隔离级别。 表示同时只有一个事务才能访问数据 (但对于oracle, 事实并不是这样的)。 Oracle稍有不同, 一个事务访问数据时, 另一个事务并不会被挂起。但是, 另外一个事务试图去读取同一个数据, Oracle会返回Ora-08177错误消息。

现实中事务隔离级别的设置
在Spring中,隔离级别的设定, 伴随在transaction属性中。 例如:

Java代码  收藏代码
  1. <bean id= "tradingService"  ...>  
  2. ...  
  3. <property name="transactionAttributes" >  
  4. <props>  
  5. <prop key="placeTrade" >  
  6. PROPAGATION_MANDATORY,ISOLATION_SERIALIZABLE  
  7. </prop>  
  8. </props>  
  9. </property>  
  10. </bean>  



隔离级别的设定。 必须要数据库也支持, 如果数据不支持, 在数据库中会使用默认设置代替而不会抛出任何exception。 所以开发人员在设定时要注意这一点。 那当然最好是使用TransactionReadCommitted, 除非你有一个必要改变它。

XA Transaction Processing
XA接口在JTA事务中的重要性, 从异构系统中可以看出来。  例如:

Java代码  收藏代码
  1. @TransactionAttribute (TransactionAttributeType.REQUIRED)  
  2. public   void  placeFixedIncomeTrade(TradeData trade)  
  3. throws  Exception {  
  4. try  {  
  5. ...  
  6. Placement placement =  
  7. placementService.placeTrade(trade);  
  8. //JMS发送消息   
  9. placementService.sendPlacementMessage(placement);  
  10. //数据库执行更细   
  11. executionService.executeTrade(placement);  
  12. catch  (TradeExecutionException e) {  
  13. log.fatal(e);  
  14. sessionCtx.setRollbackOnly();  
  15. throw  e;  
  16. }  
  17. }  



在上面的代码中, 如果数据库执行发生exception, 但JMS消息还是会发送出去。尽管我们需要这个消息立刻被释放。 因为JMS是在一个非XA环境下的独立系统,这样就违反我们的ACDI了, 这时候, 我们需要一个全局的事务管理控制JMS和数据库。 使用X/Open XA interface, 我们可以把多个资源维护在ACDI下。 既两阶段提交。

什么时候使用XA
当有多个资源 (数据库和JMS)在同一个事务下 时候, 才使用X/Open XA Interface。

分享到:
评论

相关推荐

    智能车竞赛介绍(竞赛目标和赛程安排).zip

    全国大学生智能汽车竞赛自2006年起,由教育部高等教育司委托高等学校自动化类教学指导委员会举办,旨在加强学生实践、创新能力和培养团队精神的一项创意性科技竞赛。该竞赛至今已成功举办多届,吸引了众多高校学生的积极参与,此文件为智能车竞赛介绍

    集字卡v4.3.4微信公众号原版三种UI+关键字卡控制+支持强制关注.zip

    字卡v4.3.4 原版 三种UI+关键字卡控制+支持获取用户信息+支持强制关注 集卡模块从一开始的版本到助力版本再到现在的新规则版本。 集卡模块难度主要在于 如何控制各种不同的字卡组合 被粉丝集齐的数量。 如果不控制那么一定会出现超过数量的粉丝集到指定的字卡组合,造成奖品不够的混乱,如果大奖价值高的话,超过数量的粉丝集到大奖后,就造成商家的活动费用超支了。我们冥思苦想如何才能限制集到指定字卡组合的粉丝数,后我们想到了和支付宝一样的选一张关键字卡来进行规则设置的方式来进行限制,根据奖品所需的关键字卡数,设定规则就可以控制每种奖品所需字卡组合被粉丝集到的数量,规则可以在活动进行中根据需要进行修改,活动规则灵活度高。新版的集卡规则,在此次政府发布号的活动中经受了考验,集到指定字卡组合的粉丝没有超出规则限制。有了这个规则限制后,您无需盯着活动,建好活动后就无人值守让活动进行就行了,您只需要时不时来看下蹭蹭上涨的活动数据即可。 被封? 无需担心,模块内置有防封功能,支持隐藏主域名,显示炮灰域名,保护活动安全进行。 活动准备? 只需要您有一个认证服务号即可,支持订阅号借用认证服务号来做活动。如果您

    出口设备线体程序详解:PLC通讯下的V90控制与开源FB284工艺对象实战指南,出口设备线体程序详解:PLC通讯与V90控制集成,工艺对象与FB284协同工作,开源学习V90控制技能,出口设备1200

    出口设备线体程序详解:PLC通讯下的V90控制与开源FB284工艺对象实战指南,出口设备线体程序详解:PLC通讯与V90控制集成,工艺对象与FB284协同工作,开源学习V90控制技能,出口设备1200线体程序,多个plc走通讯,内部有多个v90,采用工艺对象与fb284 共同控制,功能快全部开源,能快速学会v90的控制 ,出口设备; 1200线体程序; PLC通讯; 多个V90; 工艺对象; FB284; 功能开源; V90控制。,V90工艺控制:开源功能快,快速掌握1200线体程序与PLC通讯

    基于Arduino与DAC8031的心电信号模拟器资料:心电信号与正弦波的双重输出应用方案,Arduino与DAC8031心电信号模拟器:生成心电信号与正弦波输出功能详解,基于arduino +DAC

    基于Arduino与DAC8031的心电信号模拟器资料:心电信号与正弦波的双重输出应用方案,Arduino与DAC8031心电信号模拟器:生成心电信号与正弦波输出功能详解,基于arduino +DAC8031的心电信号模拟器资料,可输出心电信号,和正弦波 ,基于Arduino;DAC8031;心电信号模拟器;输出心电信号;正弦波输出;模拟器资料,基于Arduino与DAC8031的心电信号模拟器:输出心电与正弦波

    (参考项目)MATLAB口罩识别检测.zip

    MATLAB口罩检测的基本流程 图像采集:通过摄像头或其他图像采集设备获取包含面部的图像。 图像预处理:对采集到的图像进行灰度化、去噪、直方图均衡化等预处理操作,以提高图像质量,便于后续的人脸检测和口罩检测。 人脸检测:利用Haar特征、LBP特征等经典方法或深度学习模型(如MTCNN、FaceBoxes等)在预处理后的图像中定位人脸区域。 口罩检测:在检测到的人脸区域内,进一步分析是否佩戴口罩。这可以通过检测口罩的边缘、纹理等特征,或使用已经训练好的口罩检测模型来实现。 结果输出:将检测结果以可视化方式展示,如在图像上标注人脸和口罩区域,或输出文字提示是否佩戴口罩。

    kernel-debug-devel-3.10.0-1160.119.1.el7.x64-86.rpm.tar.gz

    1、文件内容:kernel-debug-devel-3.10.0-1160.119.1.el7.rpm以及相关依赖 2、文件形式:tar.gz压缩包 3、安装指令: #Step1、解压 tar -zxvf /mnt/data/output/kernel-debug-devel-3.10.0-1160.119.1.el7.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm 4、更多资源/技术支持:公众号禅静编程坊

    day02供应链管理系统-补充.zip

    该文档提供了一个关于供应链管理系统开发的详细指南,重点介绍了项目安排、技术实现和框架搭建的相关内容。 文档分为以下几个关键部分: 项目安排:主要步骤包括搭建框架(1天),基础数据模块和权限管理(4天),以及应收应付和销售管理(5天)。 供应链概念:供应链系统的核心流程是通过采购商品放入仓库,并在销售时从仓库提取商品,涉及三个主要订单:采购订单、销售订单和调拨订单。 大数据的应用:介绍了数据挖掘、ETL(数据抽取)和BI(商业智能)在供应链管理中的应用。 技术实现:讲述了DAO(数据访问对象)的重用、服务层的重用、以及前端JS的继承机制、jQuery插件开发等技术细节。 系统框架搭建:包括Maven环境的配置、Web工程的创建、持久化类和映射文件的编写,以及Spring配置文件的实现。 DAO的需求和功能:供应链管理系统的各个模块都涉及分页查询、条件查询、删除、增加、修改操作等需求。 泛型的应用:通过示例说明了在Java语言中如何使用泛型来实现模块化和可扩展性。 文档非常技术导向,适合开发人员参考,用于构建供应链管理系统的架构和功能模块。

    基于四旋翼无人机的PD控制研究 附Matlab代码.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

    C#与VB实现欧姆龙PLC的Fins TCP通信案例源码:调用动态链接库进行数据读写,定时器与计数器数据区的简洁读写操作示例,C#与VB实现欧姆龙PLC的Fins TCP通信案例源码:调用动态链接库进

    C#与VB实现欧姆龙PLC的Fins TCP通信案例源码:调用动态链接库进行数据读写,定时器与计数器数据区的简洁读写操作示例,C#与VB实现欧姆龙PLC的Fins TCP通信案例源码:调用动态链接库进行读写操作,涵盖定时器计数器数据区学习案例,C#欧姆龙plc Fins Tcp通信案例上位机源码,有c#和VB的Demo,c#上位机和欧姆龙plc通讯案例源码,调用动态链接库,可以实现上位机的数据连接,可以简单实现D区W区定时器计数器等数据区的读写,是一个非常好的学习案例 ,C#; 欧姆龙PLC; Fins Tcp通信; 上位机源码; 动态链接库; 数据连接; D区W区读写; 定时器计数器; 学习案例,C#实现欧姆龙PLC Fins Tcp通信上位机源码,读写数据区高效学习案例

    可调谐石墨烯超材料吸收体的FDTD仿真模拟研究报告:吸收光谱的化学势调节策略与仿真源文件解析,可调谐石墨烯超材料吸收体:化学势调节光谱的FDTD仿真模拟研究,可调谐石墨烯超材料吸收体FDTD仿真模拟

    可调谐石墨烯超材料吸收体的FDTD仿真模拟研究报告:吸收光谱的化学势调节策略与仿真源文件解析,可调谐石墨烯超材料吸收体:化学势调节光谱的FDTD仿真模拟研究,可调谐石墨烯超材料吸收体FDTD仿真模拟 【案例内容】该案例提供了一种可调谐石墨烯超材料吸收体,其吸收光谱可以通过改变施加于石墨烯的化学势来进行调节。 【案例文件】仿真源文件 ,可调谐石墨烯超材料吸收体; FDTD仿真模拟; 化学势调节; 仿真源文件,石墨烯超材料吸收体:FDTD仿真调节吸收光谱案例解析

    RBF神经网络控制仿真-第二版

    RBF神经网络控制仿真-第二版

    松下PLC与威纶通触摸屏转盘设备控制:FPWINPRO7与EBPRO智能编程与宏指令应用,松下PLC与威纶通触摸屏转盘设备控制解决方案:FPWINPRO7与EBPRO协同工作,实现多工位转盘加工与IE

    松下PLC与威纶通触摸屏转盘设备控制:FPWINPRO7与EBPRO智能编程与宏指令应用,松下PLC与威纶通触摸屏转盘设备控制解决方案:FPWINPRO7与EBPRO协同工作,实现多工位转盘加工与IEC编程模式控制,松下PLC+威纶通触摸屏的转盘设备 松下PLC工程使用程序版本为FPWINPRO7 7.6.0.0版本 威纶通HMI工程使用程序版本为EBPRO 6.07.02.410S 1.多工位转盘加工控制。 2.国际标准IEC编程模式。 3.触摸屏宏指令应用控制。 ,松下PLC; 威纶通触摸屏; 转盘设备控制; 多工位加工控制; IEC编程模式; 触摸屏宏指令应用,松下PLC与威纶通HMI联控的转盘设备控制程序解析

    基于循环神经网络(RNN)的多输入单输出预测模型(适用于时间序列预测与回归分析,需Matlab 2021及以上版本),基于循环神经网络(RNN)的多输入单输出预测模型(matlab版本2021+),真

    基于循环神经网络(RNN)的多输入单输出预测模型(适用于时间序列预测与回归分析,需Matlab 2021及以上版本),基于循环神经网络(RNN)的多输入单输出预测模型(matlab版本2021+),真实值与预测值对比,多种评价指标与线性拟合展示。,RNN预测模型做多输入单输出预测模型,直接替数据就可以用。 程序语言是matlab,需求最低版本为2021及以上。 程序可以出真实值和预测值对比图,线性拟合图,可打印多种评价指标。 PS:以下效果图为测试数据的效果图,主要目的是为了显示程序运行可以出的结果图,具体预测效果以个人的具体数据为准。 2.由于每个人的数据都是独一无二的,因此无法做到可以任何人的数据直接替就可以得到自己满意的效果。 这段程序主要是一个基于循环神经网络(RNN)的预测模型。它的应用领域可以是时间序列预测、回归分析等。下面我将对程序的运行过程进行详细解释和分析。 首先,程序开始时清空环境变量、关闭图窗、清空变量和命令行。然后,通过xlsread函数导入数据,其中'数据的输入'和'数据的输出'是两个Excel文件的文件名。 接下来,程序对数据进行归一化处理。首先使用ma

    【图像识别】手写文字识别研究 附Matlab代码+运行结果.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

    旅游管理系统(基于springboot,mysql,java).zip

    旅游管理系统中的功能模块主要是实现管理员;首页、个人中心、用户管理、旅游方案管理、旅游购买管理、系统管理,用户;首页、个人中心、旅游方案管理、旅游购买管理、我的收藏管理。前台首页;首页、旅游方案、旅游资讯、个人中心、后台管理等功能。经过认真细致的研究,精心准备和规划,最后测试成功,系统可以正常使用。分析功能调整与旅游管理系统实现的实际需求相结合,讨论了Java开发旅游管理系统的使用。 从上面的描述中可以基本可以实现软件的功能: 1、开发实现旅游管理系统的整个系统程序;  2、管理员;首页、个人中心、用户管理、旅游方案管理、旅游购买管理、系统管理等。 3、用户:首页、个人中心、旅游方案管理、旅游购买管理、我的收藏管理。 4、前台首页:首页、旅游方案、旅游资讯、个人中心、后台管理等相应操作; 5、基础数据管理:实现系统基本信息的添加、修改及删除等操作,并且根据需求进行交流查看及回复相应操作。

    Boost二级升压光伏并网结构的Simulink建模与MPPT最大功率点追踪:基于功率反馈的扰动观察法调整电压方向研究,Boost二级升压光伏并网结构的Simulink建模与MPPT最大功率点追踪:基

    Boost二级升压光伏并网结构的Simulink建模与MPPT最大功率点追踪:基于功率反馈的扰动观察法调整电压方向研究,Boost二级升压光伏并网结构的Simulink建模与MPPT最大功率点追踪:基于功率反馈的扰动观察法调整电压方向研究,Boost二级升压光伏并网结构,Simulink建模,MPPT最大功率点追踪,扰动观察法采用功率反馈方式,若ΔP>0,说明电压调整的方向正确,可以继续按原方向进行“干扰”;若ΔP<0,说明电压调整的方向错误,需要对“干扰”的方向进行改变。 ,Boost升压;光伏并网结构;Simulink建模;MPPT最大功率点追踪;扰动观察法;功率反馈;电压调整方向。,光伏并网结构中Boost升压MPPT控制策略的Simulink建模与功率反馈扰动观察法

    基于matlab平台的图像去雾设计.zip

    运行GUI版本,可二开

    Deepseek相关参考资源文档

    Deepseek相关主题资源及行业影响

    WP Smush Pro3.16.12 一款专为 WordPress 网站设计的图像优化插件开心版.zip

    WP Smush Pro 是一款专为 WordPress 网站设计的图像优化插件。 一、主要作用 图像压缩 它能够在不影响图像质量的前提下,大幅度减小图像文件的大小。例如,对于一些高分辨率的产品图片或者风景照片,它可以通过先进的压缩算法,去除图像中多余的数据。通常 JPEG 格式的图像经过压缩后,文件大小可以减少 40% – 70% 左右。这对于网站性能优化非常关键,因为较小的图像文件可以加快网站的加载速度。 该插件支持多种图像格式的压缩,包括 JPEG、PNG 和 GIF。对于 PNG 图像,它可以在保留透明度等关键特性的同时,有效地减小文件尺寸。对于 GIF 图像,也能在一定程度上优化文件大小,减少动画 GIF 的加载时间。 懒加载 WP Smush Pro 实现了图像懒加载功能。懒加载是一种延迟加载图像的技术,当用户滚动页面到包含图像的位置时,图像才会加载。这样可以避免一次性加载大量图像,尤其是在页面内容较多且包含许多图像的情况下。例如,在一个新闻网站的长文章页面,带有大量配图,懒加载可以让用户在浏览文章开头部分时,不需要等待所有图片加载,从而提高页面的初始加载速度,同时也能

    1. Download this file: https://cdn-media.huggingface.co/frpc-gradio-0.3/frpc-windows-amd64.exe

    Could not create share link. Missing file: C:\Users\xx\.conda\envs\omni\Lib\site-packages\gradio\frpc_windows_amd64_v0.3 1. Download this file: https://cdn-media.huggingface.co/frpc-gradio-0.3/frpc_windows_amd64.exe 2. Rename the downloaded file to: frpc_windows_amd64_v0.3 3. Move the file to this location: C:\Users\xx\.conda\envs\omni\Lib\site-packages\gradio

Global site tag (gtag.js) - Google Analytics