??xml version="1.0" encoding="utf-8" standalone="yes"?>
1. ?/strong>
Hibernate 的一个扩展,用于处理多数据库水^分区架构?
由google工程?2007q?捐献l?HibernateC?nbsp;
http://www.hibernate.org/414.html
目前版本Q?nbsp; 3.0.0 beta2Q?未发GA版?
条gQHibernate Core 3.2, JDK 5.0
2. 水^分区原理
一个库表如 Order 存在于多个数据库实例上。按特定的分区逻辑Q将该库表的数据存储在这些实例中Q一条记录的主键 PKQ在所有实例中不得重复?
水^分区在大型网站,大型企业应用中经帔R用?nbsp;?a >www.sina.com.cn ,www.163.com www.bt285.cn www.guihua.org
目的Z量数据分散存储Q分散操作,分散查询以便提高数据处理量和整体数据处理性能?
使用Q?
google工程师的设计q是非常好的Q完全兼?Hibernate本n的主要接口?
因此E序员开发变化不大,甚至不需要关心后C用了分区数据库。程序迁U问题不大。而且配置上比较简明?
3. 三种{略Q?/strong>
1) ShardAccessStrategy, 查询操作Ӟ到那个分区执行?
默认提供两个实现Q?
序{略QSequentialShardAccessStrategyQ?每个query按顺序在所有分Z执行?
q{略QParallelShardAccessStrategyQ?每个query以多U程方式q发q的在所有分Z执行?此策略下Q需要用线E池机制满特定的性能需要,java.util.concurrent.ThreadPoolExecutor?
2) ShardSelectionStrategy, 新增对象Ӟ存储到哪个分区?
框架默认提供了一个轮询选择{略 RoundRobinShardSelectionStrategy, 但一般不q样使用?
通常采用“attribute-based sharding”机制Q基于属性分区。一般是用户Ҏ表自己实C个基于属性分区的{略cShardSelectionStrategy Q例如,以下WeatherReportZcontinent属性选择分区Q?
3) ShardResolutionStrategy, 该策略用于查扑֍个对象时Q判断它在哪个或哪几个分Z?
默认使用 AllShardsShardResolutionStrategy Q可以自定义例如Q?
4. 水^分区下的查询
对于单查?HibernateShard 可以满?
水^分区下多库查询是一个挑战。主要存在于以下三种操作Q?
1) distinct
因ؓ需要遍历所有shard分区Qƈq行合ƈ判断重复记录?
2) order by
cM 1)
3) aggregation
countQsimQavg{聚合操作先分散到分区执行,再进行汇怅R?
是不是有点类g MapReduce Q?呵呵?
目前 HibernateShard 不支?1), 2), ?3) 部分支持
HibernateShard 目前通过 Criteria 接口的实现对 聚合提供了较好的支持Q?因ؓ Criteria 以API接口指定?Projection 操作Q逻辑相对单?
而HQLQ原?SQL q不支持此类操作?
5. 再分区和虚拟分区
当数据库规模增大Q需要调整分区逻辑和数据存储时Q?需要再分区?
两种方式Q?1Q数据库数据q移其他分区Q?2Q?改变记录和分区映关pR这两种方式都比较麻烦。尤?#8220;改变记录和分区映关p?#8221;Q需要调?ShardResolutionStrategy?
HibernateShard 提供了一U虚拟分区层。当需要调整分区策略时Q只需要调整虚拟分区和物理分区映射关系卛_。以下是使用虚拟分区时的配置创徏q程Q?
6. 局限:
1QHibernateShard 不支持垂直分区, 垂直+水^混合分区?
2Q?水^分区?查询功能受到一定限Ӟ有些功能不支持。实践中Q需要在应用层面Ҏq_区算法进行更多的考虑?
3Q?不支持跨分区?关系 操作。例如:删除A分区上的 s 表,B分区上的兌子表 t的记录无法进行参照完整性约束检查?Q其实这个相?跨分区查询的挑战应该说小的多Q也许google工程师下个版本会支持Q呵呵)
4) 解析{略接口g和对象ID全局唯一性有些自相矛盾,
AllShardsShardResolutionStrategy 的接口返回的是给定对象ID所在的 shard ID集合Q按理应该是明确的一?shard ID.
参考资料:HibernateShard 参考指南?
]]>
经U度转换成十q制
公式Q?br />
Decimal Degrees = Degrees + minutes/60 + seconds/3600
例:57°55'56.6" =57+55/60+56.6/3600=57.9323888888888
如把l纬?nbsp; (longitudeQlatitude) (205.395583333332Q?7.9323888888888)转换据成坐标(Degrees,minutes,seconds)(205°23'44.1"Q?7°55'56.6")?/span>
步骤如下Q?/span>
1?直接d"?Q?span style="font-size: small">205
2?205.395583333332-205)*60=23.734999999920 得到"?Q?span style="font-size: small">23
3?23.734999999920-23)*60=44.099999995200 得到"U?Q?span style="font-size: small">44.1
发送定位指令,l端q回的经U度信息如下Q?/span>
(ONE072457A3641.2220N11706.2569E000.000240309C0000400)
按照协议解析
获得信息体的l纬度是主要Q其它不要管Q直接用Stringcȝsubstring()Ҏ截掉Q获取的l纬?/span>
3641.2220N11706.2569E http://www.bt285.cn
q行l果
一、本囄生成器具有以下功能特性:
1、可以设|图片的宽度、高度、外框颜艌Ӏ背景色Q?/p>
2、可以设|图片字体的大小、名U、颜Ԍ
3、可以设|输出图片的格式Q如JPEG、GIF{;
4、可以将囄存储C个文件或者存储到一个输出流Q?/p>
5、可以ؓ囄增加若干条干扰线Q在生成随机码图片时可用此特性)Q?/p>
6、打印在囄上的文字支持自动换行Q?/p>
另外Q本囄生成器还用到了模板方法模式?/p>
二、下面列出相关的源代?/p>
1、抽象类AbstractImageCreator的源代码
2、类DefaultImageCreator的源代码
该类生成的囄存储C个文件中Q需要设|outputFilePath成员变量|该成员变量DC图片的存储全\径?/p>
3、类OutputStreamImageCreator的源代码
该类生成的囄存储C个输出流中,需要设|out成员变量倹{?/p>
三、实例代?/p>
1、图片存储到文g
对于传统的C或C++之类的语a来说Q要在Web上保护源代码是很Ҏ的,只要不发布它可以。遗憄是,JavaE序的源代码很容易被别hL。只要有一个反~译器,M人都可以分析别h的代码。Java的灵zL得源代码很容易被H取Q但与此同时Q它也通过加密保护代码变得相对ҎQ我们唯一需要了解的是Java的ClassLoader对象。当Ӟ在加密过E中Q有关Java Cryptography Extension(JCE)的知识也是必不可的?/p>
有几U技术可?#8220;模糊”JavacLӞ使得反编译器处理cL件的效果大打折扣。然而,修改反编译器使之能够处理q些l过模糊处理的类文gq不是什么难事,所以不能简单地依赖模糊技术来保证源代码的安全?/p>
我们可以用流行的加密工具加密应用Q比?a >PGP(Pretty Good Privacy)或GPG(GNU Privacy Guard)。这Ӟ最l用户在q行应用之前必须先进行解密。但解密之后Q最l用户就有了一份不加密的类文gQ这和事先不q行加密没有什么差别?/p>
Javaq行时装入字节码的机刉含地意味着可以对字节码q行修改。JVM每次装入cL件时都需要一个称为ClassLoader的对象,q个对象负责把新的类装入正在q行的JVM。JVMlClassLoader一个包含了待装入类(比如java.lang.Object)名字的字W串Q然后由ClassLoader负责扑ֈcLӞ装入原始数据Qƈ把它转换成一个Class对象?/p>
我们可以通过定制ClassLoaderQ在cL件执行之前修改它。这U技术的应用非常q泛??在这里,它的用途是在类文g装入之时q行解密Q因此可以看成是一U即时解密器。由于解密后的字节码文g永远不会保存到文件系l,所以窃密者很隑־到解密后的代码?/p>
׃把原始字节码转换成Class对象的过E完全由pȝ负责Q所以创建定制ClassLoader对象其实q不困难Q只需先获得原始数据,接着可以进行包含解密在内的M转换?/p>
Java 2在一定程度上化了定制ClassLoader的构建。在Java 2中,loadClass的缺省实C旧负责处理所有必需的步骤,但ؓ了顾及各U定制的c装入过E,它还调用一个新的findClassҎ?/p>
qؓ我们~写定制的ClassLoader提供了一条捷径,减少了麻烦:只需覆盖findClassQ而不是覆盖loadClass。这U方法避免了重复所有装入器必需执行的公共步骤,因ؓq一切由loadClass负责?/p>
不过Q本文的定制ClassLoaderq不使用q种Ҏ。原因很单。如果由默认的ClassLoader先寻扄q加密的cLӞ它可以找?但由于类文g已经加密Q所以它不会认可q个cLӞ装入q程失败。因此,我们必须自己实现loadClassQ稍微增加了一些工作量?/p>
二、定制类装入?/strong>
每一个运行着的JVM已经拥有一个ClassLoader。这?a >默认的ClassLoaderҎCLASSPATH环境变量的|在本地文件系l中L合适的字节码文件?/p>
应用定制ClassLoader要求对这个过E有较ؓ深入的认识。我们首先必dZ个定制ClassLoadercȝ实例Q然后显式地要求它装入另外一个类。这强制JVM把该cM及所有它所需要的cd联到定制的ClassLoader。Listing 1昄了如何用定制ClassLoader装入cL件?/p>
【Listing 1Q利用定制的ClassLoader装入cL件?/p>
以下是引用片D:
// 首先创徏一个ClassLoader对象 ?http://www.bt285.cn ClassLoader myClassLoader = new myClassLoader(); // 利用定制ClassLoader对象装入cL? // q把它{换成Class对象 Class myClass = myClassLoader.loadClass( "mypackage.MyClass" ); // 最后,创徏该类的一个实? Object newInstance = myClass.newInstance(); // 注意QMyClass所需要的所有其他类Q都通过 // 定制的ClassLoader自动装入 |
如前所qͼ定制ClassLoader只需先获取类文g的数据,然后把字节码传递给q行时系l,由后者完成余下的d?/p>
ClassLoader有几个重要的Ҏ。创建定制的ClassLoaderӞ我们只需覆盖其中的一个,即loadClassQ提供获取原始类文g数据的代码。这个方法有两个参数Q类的名字,以及一个表CJVM是否要求解析cd字的标记(x否同时装入有依赖关系的类)。如果这个标记是trueQ我们只需在返回JVM之前调用resolveClass?/p>
【Listing 2QClassLoader.loadClass()的一个简单实现?/p>
以下是引用片D:
public Class loadClass( String name, boolean resolve ) 如:http://www.5a520.cn throws ClassNotFoundException { try { // 我们要创建的Class对象 Class clasz = null; // 必需的步?Q如果类已经在系l缓冲之中, // 我们不必再次装入? clasz = findLoadedClass( name ); if (clasz != null) return clasz; // 下面是定刉? byte classData[] = /* 通过某种Ҏ获取字节码数?*/; if (classData != null) { // 成功d字节码数据,现在把它转换成一个Class对象 clasz = defineClass( name, classData, 0, classData.length ); } // 必需的步?Q如果上面没有成功, // 我们试用默认的ClassLoader装入? if (clasz == null) clasz = findSystemClass( name ); // 必需的步?Q如有必要,则装入相关的c? if (resolve && clasz != null) resolveClass( clasz ); // 把类q回l调用? return clasz; } catch( IOException ie ) { throw new ClassNotFoundException( ie.toString() ); } catch( GeneralSecurityException gse ) { throw new ClassNotFoundException( gse.toString() ); } } |
findLoadedClassQ用来进行检查,以便认被请求的cd前还不存在。loadClassҎ应该首先调用它?/p>
defineClassQ获得原始类文g字节码数据之后,调用defineClass把它转换成一个Class对象。Q何loadClass实现都必调用这个方法?/p>
findSystemClassQ提供默认ClassLoader的支持。如果用来寻扄的定制方法不能找到指定的c?或者有意地不用定制Ҏ)Q则可以调用该方法尝试默认的装入方式。这是很有用的,特别是从普通的JAR文g装入标准JavacL?/p>
resolveClassQ当JVM惌装入的不仅包括指定的c,而且q包括该cd用的所有其他类Ӟ它会把loadClass的resolve参数讄成true。这Ӟ我们必须在返回刚刚装入的Class对象l调用者之前调用resolveClass?/p>
三、加密、解?/strong>
Java加密扩展即Java Cryptography ExtensionQ简UJCE。它是Sun的加密服务YӞ包含了加密和密匙生成功能。JCE是JCA(Java Cryptography Architecture)的一U扩展?/p>
JCE没有规定具体的加密算法,但提供了一个框Ӟ加密法的具体实现可以作为服务提供者加入。除了JCE框架之外QJCE软g包还包含了SunJCE服务提供者,其中包括许多有用的加密算法,比如DES(Data Encryption Standard)和Blowfish?/p>
为简单计Q在本文中我们将用DES法加密和解密字节码。下面是用JCE加密和解密数据必遵循的基本步骤Q?/p>
步骤1Q生成一个安全密匙。在加密或解密Q何数据之前需要有一个密匙。密匙是随同被加密的应用一起发布的一段数据QListing 3昄了如何生成一个密匙?【Listing 3Q生成一个密匙?/p>
以下是引用片D:
// DES法要求有一个可信Q的随机数? SecureRandom sr = new SecureRandom(); // 为我们选择的DES法生成一个KeyGenerator对象 KeyGenerator kg = KeyGenerator.getInstance( "DES" ); kg.init( sr ); // 生成密匙 SecretKey key = kg.generateKey(); // 获取密匙数据 byte rawKeyData[] = key.getEncoded(); /* 接下来就可以用密匙进行加密或解密Q或者把它保? 为文件供以后使用 */ doSomething( rawKeyData ); |
以下是引用片D:
// DES法要求有一个可信Q的随机数? SecureRandom sr = new SecureRandom(); byte rawKeyData[] = /* 用某U方法获得密匙数?*/; // 从原始密匙数据创建DESKeySpec对象 DESKeySpec dks = new DESKeySpec( rawKeyData ); // 创徏一个密匙工厂,然后用它把DESKeySpec转换? // 一个SecretKey对象 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance( "DES" ); SecretKey key = keyFactory.generateSecret( dks ); // Cipher对象实际完成加密操作 Cipher cipher = Cipher.getInstance( "DES" ); // 用密匙初始化Cipher对象 cipher.init( Cipher.ENCRYPT_MODE, key, sr ); // 现在Q获取数据ƈ加密 byte data[] = /* 用某U方法获取数?*/ // 正式执行加密操作 byte encryptedData[] = cipher.doFinal( data ); // q一步处理加密后的数? doSomething( encryptedData ); |
// DES法要求有一个可信Q的随机数? SecureRandom sr = new SecureRandom(); byte rawKeyData[] = /* 用某U方法获取原始密匙数?*/; // 从原始密匙数据创Z个DESKeySpec对象 DESKeySpec dks = new DESKeySpec( rawKeyData ); // 创徏一个密匙工厂,然后用它把DESKeySpec对象转换? // 一个SecretKey对象 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance( "DES" ); SecretKey key = keyFactory.generateSecret( dks ); // Cipher对象实际完成解密操作 Cipher cipher = Cipher.getInstance( "DES" ); // 用密匙初始化Cipher对象 cipher.init( Cipher.DECRYPT_MODE, key, sr ); // 现在Q获取数据ƈ解密 byte encryptedData[] = /* 获得l过加密的数?*/ // 正式执行解密操作 byte decryptedData[] = cipher.doFinal( encryptedData ); // q一步处理解密后的数? doSomething( decryptedData ); |
四、应用实?/strong>
前面介绍了如何加密和解密数据。要部v一个经q加密的应用Q步骤如下:
步骤1Q创建应用。我们的例子包含一个AppȝQ两个辅助类(分别UCؓFoo和Bar)。这个应用没有什么实际功用,但只要我们能够加密这个应用,加密其他应用也就不在话下?/p>
步骤2Q生成一个安全密匙。在命o行,利用GenerateKey工具(参见GenerateKey.java)把密匙写入一个文Ӟ % java GenerateKey key.data
步骤3Q加密应用。在命o行,利用EncryptClasses工具(参见EncryptClasses.java)加密应用的类Q?% java EncryptClasses key.data App.class Foo.class Bar.class
该命令把每一?class文g替换成它们各自的加密版本?/p>
步骤4Q运行经q加密的应用。用户通过一个DecryptStartE序q行l过加密的应用。DecryptStartE序如Listing 6所C?【Listing 6QDecryptStart.javaQ启动被加密应用的程序?/p>
以下是引用片D:
import java.io.*; import java.security.*; import java.lang.reflect.*; import javax.crypto.*; import javax.crypto.spec.*; public class DecryptStart extends ClassLoader { // q些对象在构造函C讄Q? // 以后loadClass()Ҏ利用它们解密类 private SecretKey key; private Cipher cipher; // 构造函敎ͼ讄解密所需要的对象 public DecryptStart( SecretKey key ) throws GeneralSecurityException, IOException { this.key = key; String algorithm = "DES"; SecureRandom sr = new SecureRandom(); System.err.println( "[DecryptStart: creating cipher]" ); cipher = Cipher.getInstance( algorithm ); cipher.init( Cipher.DECRYPT_MODE, key, sr ); } // mainq程Q我们要在这里读入密匙,创徏DecryptStart? // 实例Q它是我们的定制ClassLoader? // 讄好ClassLoader以后Q我们用它装入应用实例, // 最后,我们通过Java Reflection API调用应用实例的mainҎ static public void main( String args[] ) throws Exception { String keyFilename = args[0]; String appName = args[1]; // q些是传递给应用本n的参? String realArgs[] = new String[args.length-2]; System.arraycopy( args, 2, realArgs, 0, args.length-2 ); // d密匙 System.err.println( "[DecryptStart: reading key]" ); byte rawKey[] = Util.readFile( keyFilename ); DESKeySpec dks = new DESKeySpec( rawKey ); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance( "DES" ); SecretKey key = keyFactory.generateSecret( dks ); // 创徏解密的ClassLoader DecryptStart dr = new DecryptStart( key ); // 创徏应用ȝ的一个实? // 通过ClassLoader装入? System.err.println( "[DecryptStart: loading "+appName+"]" ); Class clasz = dr.loadClass( appName ); // 最后,通过Reflection API调用应用实例 // 的main()Ҏ // 获取一个对main()的引? String proto[] = new String[1]; Class mainArgs[] = { (new String[1]).getClass() }; Method main = clasz.getMethod( "main", mainArgs ); // 创徏一个包含main()Ҏ参数的数l? Object argsArray[] = { realArgs }; System.err.println( "[DecryptStart: running "+appName+".main()]" ); // 调用main() main.invoke( null, argsArray ); } public Class loadClass( String name, boolean resolve ) throws ClassNotFoundException { try { // 我们要创建的Class对象 Class clasz = null; // 必需的步?Q如果类已经在系l缓冲之? // 我们不必再次装入? clasz = findLoadedClass( name ); if (clasz != null) return clasz; // 下面是定刉? try { // dl过加密的类文g byte classData[] = Util.readFile( name+".class" ); if (classData != null) { // 解密... byte decryptedClassData[] = cipher.doFinal( classData ); // ... 再把它{换成一个类 clasz = defineClass( name, decryptedClassData, 0, decryptedClassData.length ); System.err.println( "[DecryptStart: decrypting class "+name+"]" ); } } catch( FileNotFoundException fnfe ) // 必需的步?Q如果上面没有成? // 我们试用默认的ClassLoader装入? if (clasz == null) clasz = findSystemClass( name ); // 必需的步?Q如有必要,则装入相关的c? if (resolve && clasz != null) resolveClass( clasz ); // 把类q回l调用? return clasz; } catch( IOException ie ) { throw new ClassNotFoundException( ie.toString() ); } catch( GeneralSecurityException gse ) { throw new ClassNotFoundException( gse.toString() ); } } } |
对于l过加密的应用,则相应的q行方式为: % java DecryptStart key.data App arg0 arg1 arg2
DecryptStart有两个目的。一个DecryptStart的实例就是一个实施即时解密操作的定制ClassLoader;同时QDecryptStartq包含一个mainq程Q它创徏解密器实例ƈ用它装入和运行应用。示例应用App的代码包含在App.java、Foo.java和Bar.java内。Util.java是一个文件I/O工具Q本文示例多处用C它。完整的代码请从本文最后下载?/p>
五、注意事?/strong>
我们看到Q要在不修改源代码的情况下加密一个Java应用是很Ҏ的。不q,世上没有完全安全的系l。本文的加密方式提供了一定程度的源代码保护,但对某些d来说它是脆弱的?/p>
虽然应用本nl过了加密,但启动程序DecryptStart没有加密。攻击者可以反~译启动E序q修改它Q把解密后的cL件保存到盘。降低这U风险的办法之一是对启动E序q行高质量的模糊处理。或者,启动E序也可以采用直接编译成机器语言的代码,使得启动E序h传统执行文g格式的安全性?/p>
另外q要C的是Q大多数JVM本nq不安全。狡猄黑客可能会修改JVMQ从ClassLoader之外获取解密后的代码q保存到盘Q从而绕q本文的加密技术。Java没有为此提供真正有效的补救措施?/p>
不过应该指出的是Q所有这些可能的d都有一个前提,q就是攻击者可以得到密匙。如果没有密匙,应用的安全性就完全取决于加密算法的安全性。虽然这U保护代码的ҎUC上十全十,但它仍不׃ؓ一U保护知识权和敏感用户数据的有效方案?/p>
( 一 )以字节ؓ导向?stream------InputStream/OutputStream
InputStream ?OutputStream 是两?abstact c,对于字节为导向的 stream 都扩展这两个鸡肋Q基c?^_^ Q?;
1?InputStream
1.1
ByteArrayInputStream -- 把内存中的一个缓冲区作ؓ InputStream 使用 . 如?a >http://www.5a520.cn
construct---
(A)ByteArrayInputStream(byte[]) 创徏一个新字节数组输入( ByteArrayInputStream Q,它从指定字节数组中读取数据( 使用 byte 作ؓ其缓冲区数组Q?
(B)---ByteArrayInputStream(byte[], int, int) 创徏一个新字节数组输入,它从指定字节数组中读取数据?
---mark:: 该字节数l未被复制?
1.2
StringBufferInputStream -- 把一?String 对象作ؓ InputStream .
construct---
StringBufferInputStream(String) 据指定串创徏一个读取数据的输入串?
注释Q不推荐使用 StringBufferInputStream Ҏ?此类不能字W正的转换为字节?
?JDK 1.1 版中的类|从一个串创徏一个流的最x法是采用 StringReader cR?
1.3
FileInputStream -- 把一个文件作?InputStream Q实现对文g的读取操?
construct---
(A)FileInputStream(File name) 创徏一个输入文件流Q从指定?File 对象d数据?
(B)FileInputStream(FileDescriptor) 创徏一个输入文件流Q从指定的文件描q器d数据?
(C)-FileInputStream(String name) 创徏一个输入文件流Q从指定名称的文件读取数据?
method ---- read() 从当前输入流中读取一字节数据?
read(byte[]) 当前输入流?b.length 个字节数据读C个字节数l中?
read(byte[], int, int) 输入流?len 个字节数据读入一个字节数l中?
1.4
PipedInputStream Q实C pipe 的概念,主要在线E中使用 . 道输入是指一个通讯道的接收端?
一个线E通过道输出发送数据,而另一个线E通过道输入读取数据,q样可实C个线E间的通讯?
construct---
PipedInputStream() 创徏一个管道输入流Q它q未与一个管道输出流q接?
PipedInputStream(PipedOutputStream) 创徏一个管道输入流 , 它已q接C个管道输出流?
1.5
SequenceInputStream Q把多个 InputStream 合ƈZ?InputStream . “序列输入?#8221;cd许应用程序把几个输入连l地合ƈhQ?
q且使它们像单个输入一样出现。每个输入流依次被读取,直到到达该流的末?
然后“序列输入?#8221;cd闭这个流q自动地切换C一个输入流?
construct---
SequenceInputStream(Enumeration) 创徏一个新的序列输入流Qƈ用指定的输入的枚D值初始化它?
SequenceInputStream(InputStream, InputStream) 创徏一个新的序列输入流Q初始化为首?读输入流 s1, 然后读输入流 s2 ?
2?OutputSteam http://www.bt285.cn
2.1
ByteArrayOutputStream Q?把信息存入内存中的一个缓冲区?. 该类实现一个以字节数组形式写入数据的输出流?
当数据写入缓冲区Ӟ它自动扩大。用 toByteArray() ?toString() 能检索数据?
constructor
(A)--- ByteArrayOutputStream() 创徏一个新的字节数l输出流?
(B)--- ByteArrayOutputStream() 创徏一个新的字节数l输出流?
(C)--- ByteArrayOutputStream(int) 创徏一个新的字节数l输出流Qƈ带有指定大小字节的缓冲区定w?
toString(String) Ҏ指定字符~码缓冲区内容转换为字W串Qƈ字节{换ؓ字符?
write(byte[], int, int) 指定字节数l中从偏U量 off 开始的 len 个字节写入该字节数组输出?
write(int) 指定字节写入该字节数组输出?
writeTo(OutputStream) ?out.write(buf, 0, count) 调用输出的写方法将该字节数l输出流的全部内容写入指定的输出参数?
2.2
FileOutputStream: 文g输出是?File ?FileDescriptor 输出数据的一个输出流?
constructor
(A)FileOutputStream(File name) 创徏一个文件输出流Q向指定?File 对象输出数据?
(B)FileOutputStream(FileDescriptor) 创徏一个文件输出流Q向指定的文件描q器输出数据?
(C)FileOutputStream(String name) 创徏一个文件输出流Q向指定名称的文件输出数据?
(D)FileOutputStream(String, boolean) 用指定系l的文g名,创徏一个输出文件?
2.3
PipedOutputStream: 道输出是指一个通讯道的发送端?一个线E通过道输出发送数据,
而另一个线E通过道输入读取数据,q样可实C个线E间的通讯?
constructor
(A)PipedOutputStream() 创徏一个管道输出流Q它q未与一个管道输入流q接?
(B)PipedOutputStream(PipedInputStream) 创徏一个管道输出流Q它已连接到一个管道输入流?
( ?)以字Wؓ导向?stream Reader/Writer
?Unicode 字符为导向的 stream Q表CZ Unicode 字符为单位从 stream 中读取或往 stream 中写入信息?
Reader/Writer ?abstact c?
?Unicode 字符为导向的 stream 包括下面几种cdQ?
1. Reader
1.1
CharArrayReader Q与 ByteArrayInputStream 对应此类实现一个可用作字符输入的字符~冲?
constructor
CharArrayReader(char[]) 用指定字W数l创Z?CharArrayReader ?
CharArrayReader(char[], int, int) 用指定字W数l创Z?CharArrayReader
1.2
StringReader Q??StringBufferInputStream 对应其源Z个字W串的字W流?
StringReader(String) 创徏一新的串读取者?/p>
1.3
FileReader Q??FileInputStream 对应
1.4
PipedReader Q与 PipedInputStream 对应
2. Writer
2.1 CharArrayWrite Q??ByteArrayOutputStream 对应
2.2 StringWrite Q无与之对应的以字节为导向的 stream
2.3 FileWrite Q??FileOutputStream 对应
2.4 PipedWrite Q与 PipedOutputStream 对应
3、两U不同导向的 stream 之间的{?nbsp;
3.1
InputStreamReader ?OutputStreamReader Q?
把一个以字节为导向的 stream 转换成一个以字符为导向的 stream ?
InputStreamReader cL从字节流到字W流的桥梁:它读入字节,q根据指定的~码方式Q将之{换ؓ字符?
使用的编码方式可能由名称指定Q或q_可接受的~省~码方式?
InputStreamReader ?read() Ҏ之一的每ơ调用,可能促从基本字节输入流中读取一个或多个字节?
Z辑ֈ更高效率Q考虑?BufferedReader 装 InputStreamReader Q?
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
例如Q?// 实现从键盘输入一个整?
InputStreamReader(InputStream) 用缺省的字符~码方式Q创Z?InputStreamReader ?
InputStreamReader(InputStream, String) 用已命名的字W编码方式,创徏一?InputStreamReader ?
OutputStreamWriter 多个字W写入到一个输出流Q根据指定的字符~码多个字W{换ؓ字节?
每个 OutputStreamWriter 合ƈ它自q CharToByteConverter, 因而是从字W流到字节流的桥梁?/p>
Q三QJava IO 的一般用原?Q?nbsp;
一、按数据来源Q去向)分类Q?
1 、是文gQ?FileInputStream, FileOutputStream, ( 字节?)FileReader, FileWriter( 字符 )
2 、是 byte[] Q?ByteArrayInputStream, ByteArrayOutputStream( 字节?)
3 、是 Char[]: CharArrayReader, CharArrayWriter( 字符?)
4 、是 String: StringBufferInputStream, StringBufferOuputStream ( 字节?)StringReader, StringWriter( 字符?)
5 、网l数据流Q?InputStream, OutputStream,( 字节?) Reader, Writer( 字符?)
二、按是否格式化输出分Q?
1 、要格式化输出: PrintStream, PrintWriter
三、按是否要缓冲分Q?
1 、要~冲Q?BufferedInputStream, BufferedOutputStream,( 字节?) BufferedReader, BufferedWriter( 字符?)
四、按数据格式分:
1 、二q制格式Q只要不能确定是U文本的Q?: InputStream, OutputStream 及其所有带 Stream l束的子c?
2 、纯文本格式Q含U英文与汉字或其他编码方式)Q?Reader, Writer 及其所有带 Reader, Writer 的子c?
五、按输入输出分:
1 、输入: Reader, InputStream cd的子c?
2 、输出: Writer, OutputStream cd的子c?
六、特D需要:
1 、从 Stream ?Reader,Writer 的{换类Q?InputStreamReader, OutputStreamWriter
2 、对象输入输出: ObjectInputStream, ObjectOutputStream
3 、进E间通信Q?PipeInputStream, PipeOutputStream, PipeReader, PipeWriter
4 、合q输入: SequenceInputStream
5 、更Ҏ的需要: PushbackInputStream, PushbackReader, LineNumberInputStream, LineNumberReader
军_使用哪个cM及它的构造进E的一般准则如下(不考虑Ҏ需要)Q?
首先Q考虑最原始的数据格式是什么: 原则?
W二Q是输入q是输出Q原则五
W三Q是否需要{换流Q原则六W?1 ?
W四Q数据来源(dQ是什么:原则一
W五Q是否要~冲Q原则三 Q特别注明:一定要注意的是 readLine() 是否有定义,有什么比 read, write 更特D的输入或输出方法)
W六Q是否要格式化输出:原则?
朋友L(Windows 2003 + IIS + PHP + MYSQL )q来 MySQL 服务q程 (mysqld-nt.exe) CPU 占用率Mؓ 100% 高居不下。此L?0个左右的 database, 分别l十个网站调用。据朋友试Q导?mysqld-nt.exe cpu 占用奇高的是|站AQ一旦在 IIS 中将此网站停止服务,CPU 占用降下来了。一启用Q则马上上升?/p>
今天早上仔细查了一下。目前此说|站 http://www.5a520.cn 的七日^均日 IP ?000QPageView ?3万左叟뀂网站A 用的 database 目前?9个表Q记录数 60.1万条Q占I间 45MB。按q个数据QMySQL 不可能占用这么高的资源?/p>
于是在服务器上运行命令,?mysql 当前?strong>环境变量输出到文?output.txtQ?/p>
d:\web\mysql> mysqld.exe --help >output.txt
发现 tmp_table_size 的值是默认?32MQ于是修?My.ini, ?tmp_table_size 赋值到 200M:
d:\web\mysql> notepad c:\windows\my.ini [mysqld] tmp_table_size=200M
然后重启 MySQL 服务。CPU 占用有轻微下降,以前的CPU 占用波Ş图是 100% 一根直U,现在则在 97%~100%之间起伏。这表明调整 tmp_table_size 参数?MYSQL 性能提升有改善作?/strong>。但问题q没有完全解冟?/p>
于是q入 mysql ?shell 命o行,调用 show processlist, 查看当前 mysql 使用频繁?sql 语句Q?/p>
反复调用此命令,发现|站 A 的两?SQL 语句l常?process list 中出玎ͼ其语法如下: 调用 show columns 查这三个表的l构 : l于发现了问题所在:_mydata 表,只根?pid 建立了一?primary keyQ但q没有ؓ userid 建立索引。而在q个 SQL 语句的第一?LEFT JOIN ON 子句中: _mydata ?userid 被参与了条g比较q算。于是我为给 _mydata 表根据字D?userid 建立了一个烦引: 建立此烦引之后,CPU 马上降到?80% 左右。看到找C问题所在,于是查另一个反复出现在 show processlist 中的 sql 语句Q?/p>
l检?_mydata_key 表的l构Q发现它只ؓ pid Z?primary key, 没有?keywords 建立 index。_mydata_key 目前?33 万条记录Q在没有索引的情况下?3万条记录q行文本索匹配,不耗费大量?cpu 旉才怪。看来就是针对这个表的检索出问题了。于是同样ؓ _mydata_key 表根据字D?keywords 加上索引: 建立此烦引之后,CPU立刻降了下来Q在 50%~70%之间震荡?/p>
再次调用 show prosslistQ网站A 的sql 调用很出现在l果列表中了。但发现此主行了几个 Discuz 的论坛程序, Discuz 论坛的好几个表也存在着q个问题。于是顺手一q解冻Icpu占用再次降下来了 http://www.bt285.cn BT下蝲 tmp_table_size This variable determines the maximum size for a temporary table in memory. If the table becomes too large, a MYISAM table is created on disk. Try to avoid temporary tables by optimizing the queries where possible, but where this is not possible, try to ensure temporary tables are always stored in memory. Watching the processlist for queries with temporary tables that take too long to resolve can give you an early warning that tmp_table_size needs to be upped. Be aware that memory is also allocated per-thread. An example where upping this worked for more was a server where I upped this from 32MB (the default) to 64MB with immediate effect. The quicker resolution of queries resulted in less threads being active at any one time, with all-round benefits for the server, and available memory. Ҏ mysql 的开发文?
索引 index 用于Q?
mysql> show processlist;
SELECT t1.pid, t2.userid, t3.count, t1.date
FROM _mydata AS t1
LEFT JOIN _myuser AS t3 ON t1.userid=t3.userid
LEFT JOIN _mydata_body AS t2 ON t1.pid=t3.pid
ORDER BY t1.pid
LIMIT 0,15
mysql> show columns from _myuser;
mysql> show columns from _mydata;
mysql> show columns from _mydata_body;
LEFT JOIN _myuser AS t3 ON t1.userid=t3.userid
mysql> ALTER TABLE `_mydata` ADD INDEX ( `userid` )
SELECT COUNT(*)
FROM _mydata AS t1, _mydata_key AS t2
WHERE t1.pid=t2.pid and t2.keywords = '孔雀'
mysql> ALTER TABLE `_mydata_key` ADD INDEX ( `keywords` )
解决 MYSQL CPU 占用 100% 的经验ȝ
开发h员做 SQL 数据表设计的时候,一定要通盘考虑清楚?
假定你发Z列SELECT语句Q?
mysql> SELECT * FROM tbl_name WHERE col1=val1 AND col2=val2;
如果一个多列烦引存在于col1和col2上,适当的行可以直接被取出。如果分开的单行列索引存在于col1和col2上,优化器试N过军_哪个索引找到更的行ƈ来找出更具限制性的索引q且使用该烦引取行?
]]>