1705-XML约束及反射
XML
XML:eXtends MarkUp Language。可拓展的标记语言。是可以用户自定标签的,本身没有语法约束;
功能: 配置文件
文档声明(必须写在xml第一行):<?xml version = "1.0" encoding = "UTF-8"?>
约束就是xml的书写规则
常用方法:引用外部约束文件,编写XML约束实例文档
XML约束_DTD
内部约束:在XML内部定义DTD
外部约束:在外部文件中定义dtd
本地dtd文件约束:<! DOCTYPE Students SYSTEM "Student.dtd">
网络dtd文件约束:<! DOCTYPE Students PUBLIC "名称空间" "Student.dtd">
XML约束_schema
导入xsd约束文档:
1、编写根标签
2、引入实例名称空间 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3、引入名称空间 xsi:schemaLocation="http://www.itcast.cn/xml student.xsd"
4、引入默认的名称空间
常用XML约束
//web.xml
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
//struts.xml
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
//validation.xml
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
//hbm.xml
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
//hibernate.cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
//Spring - applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
//ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
DTD的约束
* 快速入门
* 快速入门的步骤:
* 需要出现哪些标签?
* 在DTD的文件中编写元素
<!ELEMENT 元素名称 元素类型>
* 判断元素是否是复杂还是简单元素?
* 如果是简单元素:(#PCDATA) 代表是字符串
* 如果是复杂元素:(子节点)
* 需要在xml引入DTD的文件
* <!DOCTYPE 根节点 SYSTEM "DTD文件的地址">
* DTD与XML文档的关联方式
* 可以在XML的文件中直接书写DTD的代码。(**经常使用**)
<!DOCTYPE 根节点 [
DTD的代码
]>
* 引入本地的DTD文件(经常使用)
<!DOCTYPE 根节点 SYSTEM "DTD文件的地址">
* 引入网络上的DTD文件
<!DOCTYPE 根节点 PUBLIC "DTD文件名称" "DTD文件的地址">
Schema(.xsd)约束
两者区别:后缀名.xsd,Schema更新数据更加完善,支持命名空间,DTD的替代者。
什么是命名空间:当文件当如多个约束文件时,且有相同标签名时,无法区分,类似java中Date类,sql和util下都有Date.
XML解析
常用的有两种DOM和SAX 解析方式
* 区别:
DOM解析XML
* 在内存中形成树状结构
* 缺点:如果文档过大,容易产生内存溢出的问题。
* 优点:方便做增删改的操作
SAX解析
* 基于事件驱动,边读边解析
* 优点:不会产生内存溢出问题。
* 缺点:不能做增删改操作。(DOM4J在内存生成树状结构)
*,只能使用DOM方式,因为SAX只能做查询。
* DOM4J 和JAXP 属于XML解析开发包
DOM4J:
*全世界都在用,开源开发包
* 企业都在用DOM4J
* 全部都可以做。
1.DOM4J的解析(必须会,企业中用的多)
1.先下载DOM4J相应的jar包。导入工程中,才能使用。
2.把dom4j-1.6.1.jar导入到工程中。
3.WEB项目:复制dom4j-1.6.1.jar到 WebRoot -- WEB-INF -- lib里面。就ok。
* DOM4J对XPATH的支持
* 导入包。jaxen-1.1-beta-6.jar。
* 怎么使用?
selectNodes("/AAA") 返回集合
selectSingleNode() 一个Node对象
* 参数就是xpath的语法
* /AAA/BBB 获取BBB的节点
* //BBB 无论层级关系,找到BBB的节点
* * 代表是所有
* /AAA/BBB[1] 找到BBB的第一个 /AAA/BBB[last()] 最后一个
* @ 属性
DOM4J扩展:
通过XML管理学生的信息。
可以在项目下建立一个xml用于存放学生信息,建一个学生类,操作类(用于对xml操作增删改查),测试类。
使用dom4j之前,必须要导入相应的jar包:必须使用SaxReader加载xml文档获得Document,通过Document获取根元素,然后就可以进行相关操作:
import java.util.List;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.Test;
public class TestDom4j {
@Test
public void testReadWebXML() {
try {
// 1.获取解析器
SAXReader saxReader = new SAXReader();
// 2.获得document文档对象
Document doc = saxReader.read("web.xml");
// 3.获取根元素
Element rootElement = doc.getRootElement();
// System.out.println(rootElement.getName());//获取根元素的名称
// System.out.println(rootElement.attributeValue("version"));//获取根元素中的属性值
// 4.获取根元素下的子元素
List<Element> childElements = rootElement.elements();
// 5.遍历子元素
for (Element element : childElements) {
//6.判断元素名称为servlet的元素
if ("servlet".equals(element.getName())) {
//7.获取servlet-name元素
Element servletName = element.element("servlet-name");
//8.获取servlet-class元素
Element servletClass = element.element("servlet-class");
System.out.println(servletName.getText());
System.out.println(servletClass.getText());
}
}
} catch (DocumentException e) {
e.printStackTrace();
}
}
}
2.JAXP的SAX解析,只能做查询,不能做增删改。
* SAX解析(原始代码)
* 解析器
//获取解析器的工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
//获取解析器对象
SAXParser sp = factory.newSAXParser();
// 解析XML(XML的文件的地址,事件处理器)
sp.parser(User.xml,new MyHander());
获取节点等去看jdk开发文档。
* DOM(原始代码)
* DocumentBuilderFactory :解析器工厂类
* DocumentBuilder 获取解析器对象
JAXP解析
* 解析XML(Document parse(String uri) )
// 获取解析器工厂类
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 获取解析器对象
DocumentBuilder builder = factory.newDocumentBuilder();
// 解析XML的文档,返回document对象
Document document = builder.parse("src/book2.xml");
* 回写
* 获取回写的工厂类
* 获取回写对象
* 调用回写的方法进行回写。
// 创建回写类的工厂
TransformerFactory transformerFactory = TransformerFactory.newInstance();
// 获取回写类
Transformer transformer = transformerFactory.newTransformer();
// 调用回写的方法
transformer.transform(new DOMSource(document), new StreamResult("src/book2.xml"));
2 .反射
1、Java反射机制(Java-Reflect):
在运行状态中,对于任意一个类,都能够知道这个类中的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java的反射机制。
反射是Java开发中一个非常重要的概念,掌握了反射的知识,才能更好的学习Java高级课程.
总之,通过反射可以对类的变量,构造方法,成员方法进行操作。
2、Java 反射机制的功能
在运行时判断任意一个对象所属的类。
在运行时构造任意一个类的对象。
在运行时判断任意一个类所具有的成员变量和方法。
在运行时调用任意一个对象的方法。
生成动态代理。
获取class对象的三种方式
获取Class对象的方式一:
通过对象具备的getClass方法(源于Object类的方法)。有点不方便,需要用到该类,并创建该类的对象,再调用getClass方法完成。
Person p = new Person();//创建Peron对象
Class clazz = p.getClass();//通过object继承来的方法(getClass)获取Person对应的字节码文件对象
获取Class对象的方式二:
每一个类型都具备一个class静态属性,通过该属性即可获取该类的字节码文件对象。比第一种简单了一些,仅用一个静态属性就搞定了。但是,还是有一点不方便,还必须要使用到该类。
Class clazz = Person.class;
#获取Class对象方式三(常用):
* 去找找Class类中是否有提供获取的方法呢?
* 找到了,static Class forName(className);
* 相对方便的多,不需要直接使用具体的类,只要知道该类的名字即可。
* 而名字完成可以作为参数进行传递 ,这样就可以提高扩展性。
* 所以为了动态获取一个类,第三种方式最为常用。
Class clazz = Class.forName("com.it.Reflect.Person");//必须类全名
创建Person对象的方式
以前:1,先加载com.it.Reflect.Person类进内存。
2,将该类封装成Class对象。
3,根据Class对象,用new操作符创建com.it.Reflect.Person对象。
4,调用构造函数对该对象进行初始化。
com.it.Reflect.Personp = new com.it.Reflect.Person();
通过方式三:(此外还可以使用构造,构造可以指定参数---如String.class)
String className = "com.it.Reflect.Person";
//1,根据名称获取其对应的字节码文件对象
1,通过forName()根据指定的类名称去查找对应的字节码文件,并加载进内存。
2,并将该字节码文件封装成了Class对象。
3,直接通过newIntstance方法,完成该对象的创建。
4,newInstance方法调用就是该类中的空参数构造函数完成对象的初始化。
Class clazz = Class.forName(className);
//2,通过Class的方法完成该指定类的对象创建。
Object object = clazz.newInstance();//该方法用的是指定类中默认的空参数构造函数完成的初始化。
#清单1,获取字节码文件中的字段。
Class clazz = Class.forName("new com.it.Reflect.Person");
//获取该类中的指定字段。比如age
Field field = clazz.getDeclaredField("age");
//clazz.getField("age");
//为了对该字段进行操作,必须要先有指定类的对象。
Object obj = clazz.newInstance();
//对私有访问,必须取消对其的访问控制检查,使用AccessibleObject父类中的setAccessible的方法
field.setAccessible(true);//暴力访问。建议大家尽量不要访问私有
field.set(obj, 789);
//获取该字段的值。
Object o = field.get(obj);
System.out.println(o);
备注:getDeclaredField:获取所有属性,包括私有。
getField:获取公开属性,包括从父类继承过来的,不包括非公开方法。
#清单2,获取字节码文件中的方法。
//根据名称获取其对应的字节码文件对象
Class clazz = Class.forName("new com.it.Reflect.Person");
//调用字节码文件对象的方法getMethod获取class对象所表示的类的
公共成员方法(指定方法),参数为方法名和当前方法的参数,无需创
建对象,它是静态方法
Method method = clazz.getMethod("staticShow", null);
//调用class对象所表示的类的公共成员方法,需要指定对象和方法中
的参数列表
method.invoke(null, null);
Class clazz = Class.forName("new com.it.Reflect.Person");
//获取指定方法。
Method method = clazz.getMethod("publicShow", null);
//获取指定的类对象。
Object obj = clazz.newInstance();
method.invoke(obj, null);//对哪个对象调用方法,是参数组
好处:大大的提高了程序的扩展性。
3、Java 反射机制的应用场景
逆向代码 ,例如反编译
与注解相结合的框架 例如Retrofit
单纯的反射机制应用框架 例如EventBus
动态生成类框架 例如Gson
使用反射生成并操作对象
Class 对象可以获得该类里的方法(由 Method 对象表示)、构造器(由 Constructor 对象表示)、成员变量(由 Field 对象表示),这三个类都位于 java.lang.reflect 包下。
程序可以通过 Method 对象来执行对应的方法,
通过 Constructor 对象来调用对应的构造器创建实例,
通过 Field 对象直接访问并修改对象的成员变量值。
1、创建对象
通过反射来生成对象的两种方式:
使用 Class 对象的 newInstance() 方法来创建该 Class 对象对应类的实例。
要求:Class 对象的对应类要有默认构造器,而执行 newInstance() 方法实际上是利用默认构造器来创建该类的实例。
先使用 Class 对象获取指定的 Constructor 对象,再调用 Constructor 对象的 newInstance() 方法来创建该 Class 对象对应类的实例。
这种方式可以选择使用指定的构造器来创建实例。
通过第一种方式来创建对象是比较常见的情形,在很多的 JavaEE 框架中都需要根据配置文件信息来创建Java对象。从配置文件中读取的只是某个类的字符串类名,程序需要根据该字符串来创建对应的实例,就必须使用到反射。
这种使用配置文件来配置对象,然后由程序根据配置文件来创建对象的方式非常有用,如 Spring 框架就采用这种方式大大简化了 JavaEE 应用的开发,当然,Spring采用的是 XML 配置文件——因为 XML 配置文件能配置的信息更加的丰富。
第二种方式,利用指定的构造器来创建 Java 对象。
获取该类的 Class 对象。
利用 Class 对象的 getConstrustor() 方法来获取指定的构造器。
调用 Construstor 的 newInstance() 方法来创建 Java 对象。
1.获取该类的 Class 对象。
2.利用 Class 对象的 getConstrustor() 方法来获取指定的构造器。
3.调用 Construstor 的 newInstance() 方法来创建 Java 对象。
设计模式
目前已学已讲的设计模式:
1,装饰 : 在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。典型就是JavaIO框架。
2,单例 : 一个类有且仅有一个实例,并且自行实例化向整个系统提供。
3,简单工厂 : 专门生产势力的类,把类的实例过程抽取到一个专门的类里。
4,工厂方法 : 创建一个工厂接口和创建多个工厂实现类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了
5,适配器 : 将一个类的接口转换成客户希望的另外一个接口。典型就是GUI里各种事件的处理。
6,模版 : 定义一个操作中的算法的骨架,而将步骤延迟到子类中。
7,动态代理 : 在实现阶段不用关心代理类,而在运行阶段才指定哪一个对象。
总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
3 .利用反射实现自定义DBUtils
目的:执行sql语句,得到结果并封装数据
在这里用反射模拟DBUtils框架的query()方法:
DBUtils查询结果为单个数据
DBUtils查询结果为单行数据
DBUtils查询结果为多行数据
准备工作:
数据库驱动jar包,C3P0jar包,C3P0配置文件xml
使用用配置文件编写C3P0工具类,工具类提供获取连接,连接池及释放资源的方法
编写要封装成的bean类,提供的变量名和查询的数据列名一致,提供setXxx()方法
使用C3P0工具类和bean类编写MyDBUtils
编写C3P0工具类:
提供getConnection(),getDataSource(),release()方法
public class C3P0Utils {
// 创建连接池,以默认方式加载配置文件(必须在src包下以c3p0-config.xml命名)
private static DataSource ds = new ComboPooledDataSource();
// 提供获得连接池的方法
public static DataSource getDataSource() {
return ds;
}
// 提供获得连接的方法
public static Connection getConnection() {
Connection connection = null;
try {
connection = ds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
// 提供释放资源的方法
public static void release(ResultSet resultSet, PreparedStatement preparedStatement, Connection connection) {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
编写bean类:
提供的变量名和查询的数据列名一致,提供setXxx()方法能够进行数据存储
public class User{
private int sid;
private String name;
private int age;
private String sex;
private double price;
private int type;
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
@Override
public String toString() {
return "User [sid=" + sid + ", name=" + name + ", age=" + age + ", sex=" + sex + ", price=" + price + ", type="
+ type + "]";
}
}
使用工具类和bean类编写DBUtils类:
ResultSetMetaData getMetaData():可以获得ResultSet的所有列名
因为 PreparedStatement 对象被预编译,所以不必执行就可以知道它将返方法,而不必等待执行该对象,然后再对返回的 ResultSet 对象调用
ResultSetMetaData metaData = preparedStatement.getMetaData();
ResultSetMetaData getMetaData():
可以获得ResultSet的所有列名
获取此 ResultSet 对象的列的编号、类型和属性。
ResultSetMetaData metaData = resultSet.getMetaData();
String getColumnName(int column):获取指定列的名称。
int getColumnCount():返回此 ResultSet 对象中的列数。
for (int i = 0; i < metaData.getColumnCount(); i++) {
String columnName = metaData.getColumnName(i + 1);// 列从第一行开始,获得每一行的列名
Object object = resultSet.getObject(columnName);// 获得每一行数据中每一列的数据
}
遇到的问题:
判断方法名与set+metaData.getColumnName()后,在设置值时,price在数据库中类型为double,而我在编写bean类时设置的是int类型,因此中途发生了bug。因此一定要注意列名和方法名的类型和名字必须要一模一样
代码实现:
public class MyDBUtils {
/**
* 模拟DBUtils的query()方法的三种结果集封装方法: A:ScalarHandler处理单个数据 B:BeanHandler处理单行数据
* C:BeanListHandler处理多行数据
*
* @param <T>
* @throws Exception
*/
// 封装单行数据
public <T> Object queryScalarHandler(DataSource ds, String sql, Class<T> clazz, Object[] params) throws Exception {
// 1:加载驱动
// 2:获得连接
Connection connection = ds.getConnection();
// 3:获得执行sql语句对象
PreparedStatement preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
preparedStatement.setObject(i + 1, params[i]);// 设置占位符的值
}
// 如何取得列名?ResultSetMetaData getMetaData():获取此 ResultSet 对象的列的编号、类型和属性。
// ResultSetMetaData metaData = resultSet.getMetaData();
ResultSetMetaData metaData = preparedStatement.getMetaData();
// 4:执行sql语句,获得结果集
ResultSet resultSet = preparedStatement.executeQuery();
// 5:处理结果集
// 这里将得到的数据设置到clazz的对应值中输出
// 获取给定bean类的实例对象
T t = null;
Method[] methods = clazz.getDeclaredMethods();// 获得bean类的所有方法
while (resultSet.next()) {
t = clazz.newInstance();
// String getColumnName(int column):获取指定列的名称。
// int getColumnCount():返回此 ResultSet 对象中的列数。
for (int i = 0; i < metaData.getColumnCount(); i++) {
String columnName = metaData.getColumnName(i + 1);// 列从第一行开始,获得每一行的列名
Object object = resultSet.getObject(columnName);// 获得每一行数据中每一列的数据
// 将得到的每一个数据赋给bean类中的成员变量
for (Method method : methods) {
if (method.getName().equalsIgnoreCase("set" + columnName)) {// 如果bean类的方法名和set+列名相同
method.invoke(t, object);// bean类成员变量赋值
}
}
}
}
// 6:释放资源
C3P0Utils.release(resultSet, preparedStatement, connection);
return t;
}
// 封装多行数据,并封装成List<E>
public <E> List<E> queryBeanListHandler(DataSource ds, String sql, Class<E> clazz, Object[] params)
throws Exception {
// 1:注册驱动
// 2:获得连接
Connection connection = ds.getConnection();
// 3:获得执行sql语句的对象
PreparedStatement prepareStatement = connection.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
prepareStatement.setObject(i + 1, params[i]);// 设置占位符
}
// 获取所有列名
ResultSetMetaData metaData = prepareStatement.getMetaData();
// 4:执行sql语句
ResultSet resultSet = prepareStatement.executeQuery();
// 获取bean类中的所有方法
Method[] methods = clazz.getMethods();
// 5:处理结果集
List<E> list = new ArrayList<>();
while (resultSet.next()) {
// 获取每一列的数据赋值给bean的实体对象
E e = clazz.newInstance();
for (int i = 0; i < metaData.getColumnCount(); i++) {
// 获得每一列的当前列名
String columnName = metaData.getColumnName(i + 1);
Object object = resultSet.getObject(columnName);// 得到了每一列的数据
// 将每一列的数据赋值到bean类实体对象
// 遍历方法Method数组
for (Method method : methods) {
if (method.getName().equalsIgnoreCase("set" + columnName)) {
method.invoke(e, object);
}
}
}
list.add(e);
}
// 6:释放资源
C3P0Utils.release(resultSet, prepareStatement, connection);
return list;
}
// 查询单个数据
public Object querySigle(DataSource ds, String sql, Object[] params) throws Exception {
// 1:注册驱动
// 2:获得连接
Connection connection = ds.getConnection();
// 3:创建执行sql语句的对象
PreparedStatement prepareStatement = connection.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
prepareStatement.setObject(i + 1, params[i]);// 设置占位符
}
// 4:执行sql语句
ResultSet resultSet = prepareStatement.executeQuery();
// 5:处理结果
Object object = null;
while (resultSet.next()) {
object = resultSet.getObject(1);// 获取到得到的数据
}
// 5:释放资源
C3P0Utils.release(resultSet, prepareStatement, connection);
return object;
}
}
测试:
public class MyDBUtilsTest {
//测试单行数据:获取user表中sid为1的明星信息
@Test
public void test01() throws Exception {
MyDBUtils md = new MyDBUtils();
String sql = "select * from user where sid=?";
Object[] params = {1};
Object object = md.queryScalarHandler(C3P0Utils.getDataSource(), sql, User.class, params);
System.out.println(object);
}
//测试多行数据:获取user表的所有明星信息
@Test
public void test02() throws Exception {
String sql = "select * from user";
MyDBUtils md = new MyDBUtils();
Object[] params = {};
List<User> list = md.queryBeanListHandler(C3P0Utils.getDataSource(), sql, User.class, params);
System.out.println(list);
}
//测试多行数据:统计type为3的明星人数
@Test
public void test03() throws Exception {
MyDBUtils md = new MyDBUtils();
String sql = "select count(*) from user where type=?";
Object[] params = {3};
Object object = md.querySigle(C3P0Utils.getDataSource(), sql, params);
System.out.println(object);
}
}
测试结果:
获得单行数据
user[sid=1, name=霆锋, age=38, sex=male, price=10000.0, type=1]
获得多行数据
* [user[sid=1, name=霆锋, age=38, sex=male, price=10000.0, type=1],
* user[sid=2, name=宝宝, age=35, sex=male, price=2000.0, type=1],
* user[sid=3, name=羽凡, age=45, sex=male, price=3000.0, type=1],
* user[sid=5, name=小白, age=30, sex=female, price=8000.0, type=2],
* user[sid=6, name=房祖名, age=29, sex=male, price=8000.0, type=3],
* user[sid=7, name=柯震东, age=28, sex=male, price=500.0, type=3],
获得单个数据 2