Spring的MVC Web应用中的持久层技术
1、常规的JDBC编程实现
(1)比较糟糕的设计方案:业务层组件与数据访问组件混合在一起
我们在常规的编程实现中,经常会在业务类中既写业务逻辑处理,同时又写与底层存储媒介交互代码,使业务类变得复杂,且不便于维护。
(2)将数据访问从业务处理类中分离中,形成DAO组件
因此我们用DAO模式将业务逻辑与底层存储媒介交互分离,DAO的英文全称为Data Access Object。DAO充当业务层与持久层的交互入口。
2、Spring中的DAO程序的代码----进一步对JDBC作了简化
(1)下面为Spring中的DAO程序的代码示例。
(2)Spring对持久层的支持技术:提供一个JdbcTemplate类来实现JDBC的数据库访问,并简化其编程实现。
3、利用Spring的JdbcTemplate类来实现JDBC的数据库访问
(1)常规的JDBC的访问代码所存在的问题
JDBC 提供了还算不错的数据库抽象,但是需要用痛苦的API。这些问题包括:
●由于JDBC是一个非常基础的数据存取API,并且它封装了对关系型数据库的访问
但是我们应该承认的是,JDBC仍然属于层次较低的API,所以在使用的时候,我们不得不编写大量的代码,来完成一件简单的工作。
●需要冗长的错误处理代码来确保ResultSets,Statements以及(最重要的)Connections在使用后
关闭
这意味着对JDBC的正确使用可以快速地导致大量的代码量。它还是一个常见的错误来源。Connection leak可以在有负载的情况下快速宕掉应用程序。
●JDBC不提供异常的层次
SQLException相对来说不能说明任何问题,JDBC不提供异常的层次,而是用抛出SQLException来响应所有的错误。找出到底哪里出错了——例如,问题是死锁还是无效的SQL?——要去检查SQLState或错误代码。这意味着这些值在数据库之间是变化的。
(2)作为对比,首先让我们来看一段传统的JDBC代码:
Connection conn =null;
Statement stmt = null;
try
{
conn = dataSource.getConnection();
stmt = con.createStatement();
stmt.executeUpdate("UPDA TE userInfo SET age = 18 WHERE id = 'erica'");
}
catch(SQLException e)
{
}
finally
{
if (stmt != null)
{
try
{
stmt.close();
}
catch (SQLException ex)
{
logger.warn("Exception in closing JDBC Statement", ex);
}
}
if (conn != null)
{
try
{
conn.close();
}
catch (SQLException ex)
{
logger.warn("Exception in closing JDBC Connection", ex);
}
}
}
类似上面的代码非常常见。主要的问题体现在下面几点:
●为了执行一个SQL语句,我们必须编写这么多行的代码,而其中很多行的代码与应用逻辑并无
关
因为,我们必须自己获得Connection与Statement对象、执行SQL、捕捉异常、关闭相关的资源),并且,这样的代码还会在系统其他地方(也许是每个需要数据库访问的地方)重复出现。
●对于重复性的劳动,我们应该使其自动化
如何使其自动化呢?我们应该知道,在一般的JDBC查询功能实现中除了SQL语句的不同以及记录集的处理不同以外,大部分的查询代码都没有太大的差别,所以我们的目标就是抽取共同的部分,而把特定的部分留给开发人员自己。
于是,大家开始寻找一些设计模式以改进如此的设计,Template模式的应用是其中一种典型的改进方案。
(3)利用Spring中的JdbcTemplate类来进行数据库访问
Spring的JDBC封装,很大一部分就是借助Template模式实现,它提供了一个优秀的JDBC模板库,借助这个工具,我们可以简单有效的对传统的JDBC编码方式加以改进。
下面是借助Spring JDBC Template修改过的代码,这段代码完成了与上面代码相同的功能。
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("UPDATE user SET age = 10 WHERE id = 'erica'");
可以看到,两行代码完成了上面需要多行代码实现的功能。所有冗余的代码都通过合理的抽象汇集到了JdbcTemplate中。
(4)两者的主要不同点
Spring提供了一个JDBC抽象框架,我们可以利用它。直接使用JDBC和使用Spring的JDBC框架之间最大的区别是:
●我们不必关心数据库连接的打开和关闭、或者其它的任何语句,Spring的框架会帮我们进行这些
处理
●另一个好处是我们不用捕获任何异常
除非我们需要。Spring会把所有SQLException包装在从DataAccessException中继承的不检测的异常层次中。当然,如果需要,我们也可以捕获这个异常,但由于大多数数据库异常是无法恢复的,所以我
们可能就会让异常传到更高的层次中去。
4、Spring中的DAO组件的技术体现:对JDBC 抽象和数据存储异常分层
Spring用两种方法来解决常规的JDBC的访问代码中所出现的问题,在实践中,我们发现所有这些都确实有助于生产力的提高和更少的bug。我们常常厌恶编写JDBC代码;现在我们能够集中精力于所要执行的SQL,而不是烦杂的JDBC资源管理。
(1)提供相应的API
把冗长乏味和容易出错的异常处理从程序代码移到框架之中。框架处理所有的异常处理;程序代码能够集中精力于编写恰当的SQL和提取结果上。Spring所提供的JDBC抽象框架由四个不同的包组成:
●核心包:包含JdbcTemplate,这个类是一个基础类之一,并由Spring框架的JDBC支持提供并使用。
●数据源包:它是实现单元测试数据库存取代码的重要的一部分,其中的DriverManagerDataSource
能够以一种类似于我们已经习惯于JDBC中的用法-----只要创建一个新的
DriverManagerDataSource并且调用setter方法来设置DriverClassName,Url,Username和
Password。
●对象包:其中所包含的各个类,用于描述RDBMS查询、更改和存储过程为线程安全的、可重用的
对象。
●支持包:我们可以从这里找到SQLException翻译功能和一些工具类。
(2)为我们所要处理SQLException程序代码提供有意义的异常层次
●当Spring第一次从数据源取得一个连接时
它检查元数据以确定数据库。它使用这些信息把SQLException映射为自己从
org.springframework.dao.DataAccessException派生下来的类层次中正确的异常。
因而我们的代码可以与有意义的异常打交道,并且不需要为私有的SQLState或者错误码担心------把冗长并且易出错误的异常处理从应用程序代码移到由框架来实现。框架负责所有的异常处理;应用程序代码则能够专注于使用适当的SQL提取结果。
●Spring提供了一个重要的异常类层次,以便于我们的应用程序代码中可以使用恰当的
SQLException子类。
借助于一个抽象异常层,我们成功地实现了数据库独立性而不必改变异常处理。例如,如果我们把我们的数据库从PostgreSQL改变为Oracle,那么我们不必把异常处理从OracleDataException改变到PostgresDataException-----Spring能够捕获应用程序服务器特定的异常并抛出一个Spring数据异常。
●我们的DAO不必绑定到JDBC
当处理异常时,Spring检查来自一个数据库连接的元数据可用性以决定数据库产品。它使用这种知识来把SQLException映射到其自己异常层次中的具体的异常上。因此,我们不需要担心专门性的SQL状态或错误代码问题;Spring的数据存取异常不是JDBC特定的,因此我们的DAO不必绑定到JDBC(由于其可能抛出的异常)。
Spring的数据访问异常不是JDBC特有的,因而我们的DAO并不一定会因为它们可能抛出的异常而绑死在JDBC上。
5、Spring提供了两层次的JDBC API
(1)首先体现在org.springframework.jdbc.core包中
使用回调机制移动控制权——并且因而把错误处理和连接获取和释放——从程序的代码移到了框架
之中。这是一种不同的Inversion of Control,但是和用于配置管理的几乎有同等重要的意义。
Spring使用类似的回调机制关注其他包含特殊获取和清理资源步骤的API,例如JDO(获取和释放是由PersistenceManager完成的),事务管理(使用JTA)和JNDI。Spring中完成这些回调的类被称作template。例如,Spring的JdbcTemplate对象能够用于执行SQL查询并且在如下的列表中保存结果:JdbcTemplate template = new JdbcTemplate(dataSource);
final List names = new LinkedList();
template.query("SELECT https://www.doczj.com/doc/176338819.html, FROM USER", new RowCallbackHandler()
{
public void processRow(ResultSet rs) throws SQLException
{
names.add(rs.getString(1));
}
});
注意回调中的程序代码是能够自由抛出SQLException的:Spring将会捕捉到这些异常并且用自己的类层次重新抛出。程序的开发者可以选择哪个异常,如果有的话,被捕捉然后处理。
JdbcTemplate提供许多支持不同情景包括prepared statements和批量更新的方法。Spring的JDBC抽象有比起标准JDBC来说性能损失非常小,甚至在当应用中需要的结果集数量很大的时候。
(2)其次是org.springframework.jdbc.object包中是对JDBC的更高层次的抽象
这是建立在核心的JDBC回调功能基础之上的,但是提供了一个能够对RDBMS操作——无论是查询,更新或者是存储过程的更通用的数据访问——使用Java对象来建模的API。
MappingSqlQuery类
一个用于返回User对象的查询对象的示例代码:
class UserQuery extends MappingSqlQuery
{
public UserQuery(DataSource datasource)
{
super(datasource, "SELECT * FROM PUB_USER_ADDRESS WHERE USER_ID = ?");
declareParameter(new SqlParameter(Types.NUMERIC));
compile();
}
// Map a result set row to a Java object (下面的mapRow方法是重写的)
protected Object mapRow(ResultSet rs, int rownum) throws SQLException
{
User user = new User();
user.setId(rs.getLong("USER_ID"));
user.setForename(rs.getString("FORENAME"));
return user;
}
public User findUser(long id)
{
// Use superclass convenience method to provide strong typing
return (User) findObject(id);
}
}
6、JdbcTemplate类的编程和应用
(1)org.springframework.jdbc.core.JdbcTemplate类
(2)主要的作用
这是在JDBC核心包中最重要的类,它简化了JDBC的使用,因为它处理了资源的建立和释放。它帮助我们避免一些常见的错误,比如忘记关闭数据库连接等。它运行核心的JDBC工作流,如Statement的建立和执行,而只需要应用程序代码提供SQL和提取结果,这个类执行SQL检询、更新或者调用存储过程。
模拟结果集的迭代以及提取返回参数值。它还捕获JDBC的异常并将它们转换成org.springframework.jdbc.core包中定义的通用的、能够提取更多信息的异常系统。
另外,在实际开发中,可以将代码中硬编码的SQL语句作为Bean的一个String类型属性,借助DI机制在配置文件中定义,从而实现SQL的参数化配置。
(3)JdbcTemplate类可以脱离Spring IoC容器来使用(如应用在J2SE应用系统中)
●只需要单独使用spring-dao.jar中的类
Spring的Jdbc封装等功能基本上可以独立于Spring来使用,因为JdbcTemplate类所需要的就是一个DataSource对象(可以通过org.springframework.jdbc.datasource.DriverManagerDataSource类获得),在不使用Spring IoC容器下,我们只需要单独使用spring-dao.jar中的类。
JDBC封装类库可以脱离Spring Context独立使用,也就是说,即使系统并没有采用Spring作为结构性框架,我们也可以单独使用Spring的JDBC部分(spring-dao.jar)来改善我们的代码。
除了JdbcTemplate类之外,Spring还提供了其它的Template类,如对Hibernate、JDO、ibatis等的Template实现。
●DriverManagerDataSource类
DriverManagerDataSource和传统的JDBC访问方式一样地获得JDBC数据库连接,为了能够进行数据库的连接,我们需要指定JDBC驱动程序的类名称、以及其它的与数据库相关的特征信息。
●示例代码
dataSource.setDriverClassName(“XXXX”);
dataSource.setUrl( (“XXXX”);
dataSource.setUsername (“XXXX”);
dataSource.setPassword (“XXXX”);
JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource);
7、为JdbcTemplate提供一个DataSource的配置项目
(1)完成对DataSource的依赖和注入
为了能够使用JdbcTemplate类,我们需要为它提供一个DataSource对象,除了可以采用前面的方法直接在代码中以编程的方式来实现以外,我们还可以在Bean的定义配置文件中完成对DataSource的依赖和注入。
这样,只需要将DataSource对象作为我们的DAO类的一个属性,直接注入就可以。
可以在DAO组件UserDAO中
JdbcTemplate template = new JdbcTemplate(dataSource);
(2)也可以采用apache dhcp组件提供的DataSource实现
如果要采用apache dhcp组件提供的DataSource实现,则为其配置JDBC驱动、数据库URL、用户名和密码等参数的配置内容应该如下:
同时,在WEB-INF/lib目录下,应该包含有apache dhcp组件的DataSource实现类的*.jar文件
commons-dbcp.jar、commons-dbcp-1.2.1.jar和commons-collections.jar。
8、org.springframework.jdbc.datasource.DriverManagerDataSource类
(1)继承关系
(2)在应用时所应该注意的问题
DriverManagerDataSource类并没有真正地实现数据库连接池的功能,而是每次调用请求时都产生物理连接。因此,它一般只适用于测试,并且是独立于J2EE容器的。
9、直接将JdbcTemplate对象作为我们的DAO类的属性
Spring的JdbcTemplate一如其名称所示的,主要是借助于Template Method模式赖实现对JDBC操作的封装。因此,我们也可以直接将JdbcTemplate在bean定义配置文件中生成,当作为一个bean来注入到我们的DAO中。
(1)DAO的示例代码---该代码与数据库无关
package example;
import javax.sql.DataSource;
import java.sql.*;
import org.springframework.jdbc.core.JdbcTemplate;
public class UserDAO
{
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate)
{
this.jdbcTemplate = jdbcTemplate;
}
public void insertUser(User user)
{
jdbcTemplate.update("INSERT INTO USER V ALUES('"+ user.getId() + "', '"
+ user.getName() + "', '"
+ user.getSex() + "', '"
+ user.getAge() + "')");
}
public User queryUser(String id)
{
....
}
....
}
(2)bean定义配置文件示例
10、Spring DAO的哲学-----封装所有的数据库访问实现,包括JDBC,JDO,Hibernate等
Spring的异常一般都是RuntimeException,数据访问的根异常是DataAccessException,所有的Spring 的数据访问异常都继承DataAccessException。此外DataAccessException的nestedRuntimeException子类中,已经将所有的异常栈都进行了记录。
Spring的DAO异常对所有底层的DAO访问实现层的异常进行了统一的封装,并给出了更为有意义的异常。
CleanupFailureDataAccessException:清除失败异常
DataAccessResourceFailureException:资源访问异常
DataIntegrityViolationException:完整性约束异常
DataRetrievalFailureException:数据获取异常
DeadlockLoserDataAccessException:死锁访问异常IncorrectUpdateSemanticsDataAccessException:更新出错异常
InvalidDataAccessApiUsageException:无效数据访问API使用异常InvalidDataAccessResourceUsageException:无效数据访问资源使用异常OptimisticLockingFailureException:乐观锁失败异常
TypeMismatchDataAccessException:类型匹配失败异常
UncategorizedDataAccessException:其他原因异常
Spring使用Template和Callback模式完成了对底层实现的统一封装,其中Template负责完成那些通用的功能(处理事务、管理资源、处理异常),Callback则完成变化的那部分内容(创建statement、设定参数parameter、生成数据集result)。
利用JdbcTemplate类操作数据库
1、JdbcTemplate类中的主要方法的应用---主动获得
(1)execute方法
●方法的定义
●主要的应用功能
execute方法常常用于执行DDL形式的SQL语句
●代码示例
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
public class ExecuteAStatement
{
private JdbcTemplate jt;
private DataSource dataSource;
public void doExecute()
{
jt = new JdbcTemplate(dataSource);
jt.execute("create table mytable (id integer, name varchar(100))");
}
public void setDataSource(DataSource dataSource)
{
this.dataSource = dataSource;
}
}
(2)执行查询的各种方法:queryForInt、queryForLong、queryForObject等
●获得某个字段的值或者总行数等功能的方法
除了前面的execute方法,在JdbcTemplate类中还有许多实现查询的方法,其中也有些用来获得单个值的查询方法,如queryForInt、queryForLong queryForObject。利用这些查询方法,可以很方便地获得某个字段的值或者总行数等返回的结果。
●所应该注意的问题
但如果类型转换无效,将抛出一个InvalidDataAccessApiUsageException的异常。
●示例代码
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
public class RunAQuery {
private JdbcTemplate jdbcTemplate; private DataSource dataSource;
public int getCount() {
jdbcTemplate = new JdbcTemplate(dataSource);
int count = jdbcTemplate.queryForInt("select count(*) from mytable"); //获得总的记录数 return count; }
public String getName()
{
return name;
} public List getList() {
return rows;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource; } }
● 注意也可以采用
String name = (String) jdbcTemplate.queryForObject("SELECT name FROM USER WHERE user_id = ?", new Object[] {id}, https://www.doczj.com/doc/176338819.html,ng.String.class);
● 获得List 中的各个Map 结果的示例代码
返回的List 中包括的是Map 对象,每个Map 对象代表查询結果中的结果集,要取得某个字段的值,要使用字段名称作为key 值,例如:
List rows = jdbcTemplate.queryForList("SELECT * FROM USER"); Iterator it = rows.iterator(); //(1) while(it.hasNext()) //(2) { Map userMap = (Map) it.next(); //(3)
System.out.print(userMap.get("user_id") + "\t"); System.out.print(userMap.get("name") + "\t"); System.out.print(userMap.get("sex") + "\t");
System.out.println(userMap.get("age") + "\t"); }
(3)更新数据库的updte 方法
● 主要的作用
利用updte 方法,可以实现对数据库表中的数据进行增、删和改等操作;并且在SQL 语句中可以带参
数。
●方法的定义
●应用的示例代码
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
public class ExecuteAnUpdate
{
private JdbcTemplate jt;
private DataSource dataSource;
public void setName(int id, String name)
{
jt = new JdbcTemplate(dataSource);
jt.update("update mytable set name =? where id = ?", new Object[] {name, new Integer(id)});
}
public void setDataSource(DataSource dataSource)
{
this.dataSource = dataSource;
}
}
●所应该注意的问题
使用update方法時,我们可以在占位符上使用"?",并指定参数的序列所对应的位置。在上例中所給定的name与id是String对象,它会取代之前对应順序的"?",然后再执行SQL更新操作。
jdbcTemplate.update("INSERT INTO USER V ALUES(?, ?, ?, ?)",
new Object[] {user.getId(), user.getName(), user.getSex(), user.getAge()});
2、利用Spring中有关JDBC操作的callback方式的接口来操作数据库--------被动获得
除了大量使用Template Method来封裝一些低层次的操作细节以外,Spring也大量使用callback方式调用相应的类中的方法以提供传统的JDBC相关的的功能,使得传统的JDBC的使用者也能清楚地了解Spring 所提供的相关封装的使用。
(1)JdbcTemplate类中所涉及的各种CallBack(回调方法)
org.springframework.jdbc.core.JdbcTemplate类中的许多方法都涉及到回调(CallBack)的使用,使得整个模板结构清晰高效。
(2)RowCallbackHandler接口的应用示例
下面再给出一个实现数据库查询的示例。
final List userList = new ArrayList();
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.query("SELECT name, sex, address FROM user WHERE age > 18",new RowCallbackHandler()
{
public void processRow(ResultSet rs) throws SQLException
{
User user = new User();
user.setId(rs.getString("name"));
user.setSex(rs.getString("sex"));
user.setAddress(rs.getString("address"));
userList.add(user);
}
});
在本例种,使用了List query(String sql, PreparedStatementSetter pss, RowCallbackHandler rch) 方法。
这里传入query方法的有两个参数,第一个是Select查询语句,第二个是一个RowCallbackHandler实例,我们通过RowCallbackHandler对Select语句得到的每行记录进行解析,并为其创建一个User数据对象。实现了手动的OR映射。
(3)JDBC的PreparedStatement接口
我們可以通过实现PreparedStatementSetter接口來提供对JDBC的操作。
final String id = user.getId();
final String name = user.getName();
final String sex = user.getSex() + "";
final int age = user.getAge();
jdbcTemplate.update("INSERT INTO USER V ALUES(?, ?, ?, ?)",
new PreparedStatementSetter()
{
public void setValues(PreparedStatement ps) throws SQLException
{
ps.setString(1, id);
ps.setString(2, name);
ps.setString(3, sex);
ps.setInt(4, age);
}
});
(4)RowCallbackHandler接口
我们可以实现RowCallbackHandler接口,在查詢到数据之后先作一些处理再传回,例如下面的例子实现了手动的O/R Mapping效果。
final User user = new User();
jdbcTemplate.query("SELECT * FROM USER WHERE user_id = ?", new Object[] {id},
new RowCallbackHandler()
{
public void processRow(ResultSet rs) throws SQLException
{
user.setId(rs.getString("user_id"));
user.setName(rs.getString("name"));
user.setSex(rs.getString("sex").charAt(0));
user.setAge(rs.getInt("age"));
}
});
(5)RowMapper接口
我们更可以通过实现RowMapper接口,将手动的O/R Mapping程序代码独立出来,从而可以重用在不同的DAO类的方法之中。
●提供一个对RowMapper接口的实现类,在该类中手动实现O/R Mapping
class UserRowMapper implements RowMapper
{
public Object mapRow(ResultSet rs, int index) throws SQLException
{
User user = new User();
user.setId(rs.getString("user_id"));
user.setName(rs.getString("name"));
user.setSex(rs.getString("sex").charAt(0));
user.setAge(rs.getInt("age"));
return user;
}
}
●从而可以在不同的DAO类的方法中重用UserRowMapper
在findAllByRowMapperResultReader()方法中使用UserRowMapper:
public List findAllByRowMapperResultReader()
{
String sql = "SELECT * FROM USER";
return jdbcTemplate.query(sql, new RowMapperResultReader(new UserRowMapper()));
}
在getUser(id)方法中使用UserRowMapper:
public User getUser(final String id) throws DataAccessException
{
String sql = "SELECT * FROM USER WHERE user_id=?";
final Object[] params = new Object[] { id };
List list = jdbcTemplate.query(sql, params, new RowMapperResultReader(new UserRowMapper()));
return (User) list.get(0);
}
3、有关异常处理的问题------ 一致的异常处理
(1)DataAccessException类
在org.springframework.dao.DataAccessException类提供了对DAO方面的异常封装。
(2)定义
(3)作用
Sping提供了一个简单的把某种技术的特定的异常如SQLException转化为它自身的异常层次种的基类异常DataAccessException的方法。这些异常包装了原始的异常,所以我们不必担心会丢失任何可能造成错误的异常信息。
除了对JDBC异常进行包装以外,Spring也可以包装Hibernate的异常,把它们从专有的、Checked Exception转化为一系列抽象的runtime Exception 。这意味着,我们可以在一致的编程模型下使用JDBC 来执行某些操作。
实验:为“Spring MVCWeb应用开发”一文提供一个DAO类
1、准备本例所需要的数据库表
(1)在MS SQLServer2000中的WebStudyDB中准备一个数据库表UserInfo,其中的id为主键并且不为自动递增类型。
(2)在该表中包含一些数据
2、将JBuilder中的所配置的MS SqlServer2000的驱动程序库添加到本Project中
3、修改springapp-servlet.xml配置文件以增加对JdbcTemplate类的注入到UserLoginImple类中
注意:
本例中的UserLoginImple类其实应该属于业务处理类,为了简化,本例将业务处理和DAO操作合并为一个类UserLoginImple。
4、修改UserLoginImple类以增加一个jdbcTemplate属性,同时实现真正的对UserInfo数据库表的访问操作,UserLoginImple类代码。
package springwebapp;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationContext;
import org.springframework.beans.BeansException;
import org.springframework.jdbc.core.JdbcTemplate;
public class UserLoginImple implements UserLoginInterface, ApplicationContextAware { ApplicationListener actionEventResponse=null;
public void setActionEventResponse(ApplicationListener actionEventResponse) {
this.actionEventResponse = actionEventResponse;
}
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate)
{
this.jdbcTemplate = jdbcTemplate;
}
public UserLoginImple()
{
}
public boolean doUserLogin(String userName,String userPassword)
{
boolean okOrNot=false;
String sqlStatement="select * from UserInfo where userName='"+userName+"' and userPassWord ='"+userPassWord+"'";