当前位置: 首页 > news >正文

企业网站建设好处中国制造网简介

企业网站建设好处,中国制造网简介,延吉网站建设彩票,关键词如何确定目录标题前言一、数据库连接方式1.JDBC连接数据库2.Spring Jdbc连接数据库(JdbcTemplate)二、JdbcTemplate源码分析1.update/save功能的实现源码分析入口(关键)基础方法execute1.获取数据库连接池2.应用用户设定的输入参数3. 调用回调函数处理4. 资源释放Update中的回调函数2.q… 目录标题前言一、数据库连接方式1.JDBC连接数据库2.Spring Jdbc连接数据库(JdbcTemplate)二、JdbcTemplate源码分析1.update/save功能的实现源码分析入口(关键)基础方法execute1.获取数据库连接池2.应用用户设定的输入参数3. 调用回调函数处理4. 资源释放Update中的回调函数2.query 功能的实现源码分析入口1(关键)源码分析入口2(关键)3.queryForObject总结前言 汇总《Spring源码深度分析》持续更新中… 本章主要以Spring提供的模板类’JdbcTemplate‘为例进行源代码分析。如果有小伙伴对Spring如何支持持久化技术的理论知识感兴趣可以参考《精通Spring4.x 企业应用开发实战》第10章 Spring对Dao的支持。 一、数据库连接方式 从《精通Spring4.x 企业应用开发实战》第10章 Spring对Dao的支持 文章中我们知道目前市场上连接MySQL数据库常用的几种持久化方式有五种JDBC、Mybatis、Hibernate、JTA、JDO。 然而Spring又分别对JDBC、Hibernate、JTA、JDO提供了模板类以便快速进行持久化连接开发。其中Spring针对JDBC的模板类是’JdbcTemplate‘。 下面我们将分别对JDBC和JdbcTemplate数据库连接进行分析。 1.JDBC连接数据库 JDBC ( Java Data Base Connectivity Java 数据库连接是一种用于执行 SQL 语句的 Java API,可以为多种关系数据库提供统一访问它由一组用 Java 语言编写的类和接口组成。JDBC 为数据库开发人员提供了一个标准的 API据此可以构建更高级的工具和接口使数据库开发人员能够用纯 Java API 编写数据库应用程序并且可跨平台运行并且不受数据库供应商的限制。 JDBC 连接数据库的流程及其原理如下。 (1在开发环境中加载指定数据库的驱动程序。接下来的实验中使用的数据库是 MysQL所以需要去下载 MySQL 支持 JDBC 的驱动程序最新的版本是 mysal-conneetorjava-5.1.18-bin.jar)将下载得到的驱动程序加载进开发环境中开发环境是 MyEclipse具体示例时会讲解如何加载。 (2在Java 程序中加载驱动程序。在 Java 程序中可以通过“Class.forName(“指定数据库的驱动程序”)”的方式来加载添加到开发环境中的驱动程序例如加载 MySQL 的数据驱动程序的代码为 Class. forName(“com.mysqljdbc.Driver”)。 (3创建数据连接对象。通过 DriverManager 类创建数据库连接对象 Conneetion。DriverManager 类作用于 Java 程序和 JDBC 驱动程序之间用于检查所加载的驱动程序是否可以建立连接然后通过它的 getConnection 方法根据数据库的 URL、用户名和密码创建一个JDBC Connection 对象例如Connection connection DriverManager.getConnection(“连接数据库的 URL”“用户名”密码”)。其中URL-协议名1P 地址域名 端口数据库名称用户名和密码是指登录数据库时所使用的用户名和密码。具体示例创建 MySQL 的数据库连接代码如下 Connection connectMySQL DriverManager.getConnection (“jdbc:mysql://localhost: 3306/myuser,root,root 4创建 Statement 对象。Statement 类的主要是用于执行静态 SQL 语句并返回它所生成结果的对象。通过 Connection 对象的 createStatement()方法可以创建一个 Statement 对象。例如Statement statament connection.createStatement()。具体示例创建 Statement 对象代码如下 Statement statamentMySQL connectMySQL.createStatement ();(5调用 Statement 对象的相关方法执行相对应的 SQL 语句。通过 execuUpdate()方法来对数据更新包括插入和删除等操作例如向 staff 表中插人一条数据的代码statement.excuteUpdate( “INSERTINTO staff (name, age, sex,address,depart,worklen, wage) VALUES (‘Tom1’, 321,“M’‘china’Personnel’3”3000’”通过调用 Statement 对象的 executeQuery()方法进行数据的查询而查询结果会得到 ResulSet对象ResuSet 表示执行查询数据库后返回的数据的集合ResulSet 对象具有可以指向当前数据行的指针。通过该对象的 next()方法使得指针指向下一行然后将数据以列号或者字段名取出。如果当 next()方法返回 null则表示下一行中没有数据存在。使用示例代码如下 Resultset resultsel statement.executeQuery( “select * from staff ;(6关闭数据库连接。使用完数据库或者不需要访问数据库时通过 Connection 的 close()方法及时关闭数据连接。 2.Spring Jdbc连接数据库(JdbcTemplate) Spring 中的 JDBC 连接与直接使用 JDBC 去连接还是有所差别的Spring 对 JDBC 做了大量封裝消除了冗余代码使得开发量大大减小。下面通过一个小例子让大家简单认识 Spring中的 JDBC 操作。 二、JdbcTemplate源码分析 1.update/save功能的实现 源码分析入口(关键) 无论对哪种技术进行源码分析我们都应该先找到入口点然后顺藤摸瓜式的解读源码。 我们以上面的例子为基础开始分析 Spring 中对JDBC 的支持首先寻找整个功能的切入点在示例中我们可以看到所有的数据库操作都封装在了 UserServicelmpl 中而 UserServicelmpl中的所有数据库操作又以其内部属性 jdbcTemplate 为基础。这个jdbcTemplate 可以作为源码分析的切人点我们一起看看它是如何实现又是如何被初始化的。 在 UserServicelmpl 中 jdbcTemplate 的初始化是从 setDataSource 函数开始的DataSource实例通过参数注入DataSource 的创建过程是引入第三方的连接池这里不做过多介绍。DataSource 是整个数据库操作的基础里面封装了整个数据库的连接信息。我们首先以保存实体类为例进行代码跟踪。 对于保存一个实体类来讲在操作中我们只需要提供 SQL 语句以及语句中对应的参数和参数类型其他操作便可以交由 Spring 来完成了,这些工作到底包括什么呢进入 jdbcTemplate中的 update 方法。 Overridepublic int update(String sql, Object[] args, int[] argTypes) throws DataAccessException {return update(sql, newArgTypePreparedStatementSetter(args, argTypes));}Overridepublic int update(String sql, Nullable PreparedStatementSetter pss) throws DataAccessException {return update(new SimplePreparedStatementCreator(sql), pss);} 进人 update 方法后我们发现Spring 并不是急于进入核心处理操作而是先做足准备工作 使用 ArgTypePreparedStatementSetter 对参数与参数类型进行封装 同时又使用 SimplePreparedStatementCreator 对 SQL 语句进行封装。 至于为什么这么封装暂且留下悬念。 经过了数据封装后便可以进入了核心的数据处理代码了。 protected int update(final PreparedStatementCreator psc, Nullable final PreparedStatementSetter pss)throws DataAccessException {logger.debug(Executing prepared SQL update);// PreparedStatementCallback作为回调函数。execute 方法是最基础的操作而其他操作比如update、 query 等方法则是传人不同的 PreparedStatementCallback 参数来执行不同的逻辑return updateCount(execute(psc, ps - {try {if (pss ! null) {// ArgumentTypePreparedStatementSetter.setValue: 将参数赋值给对应的参数类型pss.setValues(ps);}// ps.executeUpdate(): JDBC-API的基本操作int rows ps.executeUpdate();if (logger.isTraceEnabled()) {logger.trace(SQL update affected rows rows);}return rows;}finally {if (pss instanceof ParameterDisposer) {((ParameterDisposer) pss).cleanupParameters();}}}, true));} 基础方法execute /*** 功能描述作为公用的method被具有个性化的方法(增删改查)调用。* execute 作为数据库操作的核心人口將大多数数据库操作相同的步骤统一封装而将个性化的操作使用参数 PreparedStatementCallback 进行回调。** param psc* param action* param closeResources* return* param T* throws DataAccessException*/Nullableprivate T T execute(PreparedStatementCreator psc, PreparedStatementCallbackT action, boolean closeResources)throws DataAccessException {Assert.notNull(psc, PreparedStatementCreator must not be null);Assert.notNull(action, Callback object must not be null);if (logger.isDebugEnabled()) {String sql getSql(psc);logger.debug(Executing prepared SQL statement (sql ! null ? [ sql ] : ));}// 获取与数据库事务相绑定的数据库连接。Connection con DataSourceUtils.getConnection(obtainDataSource());PreparedStatement ps null;try {ps psc.createPreparedStatement(con);applyStatementSettings(ps);// 执行数据库操作CRUD。处理一些通用方法外的个性化处理也就是 PreparedStatementCallback 类型的参数的doInPreparedStatement 方法的回调。T result action.doInPreparedStatement(ps);handleWarnings(ps);return result;}catch (SQLException ex) {// Release Connection early, to avoid potential connection pool deadlock// in the case when the exception translator hasnt been initialized yet.if (psc instanceof ParameterDisposer) {((ParameterDisposer) psc).cleanupParameters();}String sql getSql(psc);psc null;JdbcUtils.closeStatement(ps);ps null;// 数据库的连接释放并不是直接调用了 Connection 的API中的close 方法。考虑到存在事务的情况如果当前线程存在事务那么说明在当前线程中存在共用数据库连接这种情况下直接使用 ConnectionHolder 中的 released 方法进行连接数减一面不是真正的释放连接。DataSourceUtils.releaseConnection(con, getDataSource());con null;throw translateException(PreparedStatementCallback, sql, ex);}finally {if (closeResources) {if (psc instanceof ParameterDisposer) {((ParameterDisposer) psc).cleanupParameters();}JdbcUtils.closeStatement(ps);DataSourceUtils.releaseConnection(con, getDataSource());}}}下面我们对execute代码中重要的几个关键点进行分析。 1.获取数据库连接池 获取数据库连接也并非直接使用 dataSource.getConnection()方法那么简单同样也考虑了诸多情况。 在数据库连接方面Spring 主要考虑的是关于事务方面的处理。基于事务处理的特殊性Spring 需要保证线程中的数据库操作都是使用同一个事务连接。 public static Connection doGetConnection(DataSource dataSource) throws SQLException {Assert.notNull(dataSource, No DataSource specified);ConnectionHolder conHolder (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);if (conHolder ! null (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {conHolder.requested();if (!conHolder.hasConnection()) {logger.debug(Fetching resumed JDBC Connection from DataSource);conHolder.setConnection(fetchConnection(dataSource));}return conHolder.getConnection();}// Else we either got no holder or an empty thread-bound holder here.logger.debug(Fetching JDBC Connection from DataSource);Connection con fetchConnection(dataSource);// 功能描述判断当前线程是否存在事务。// 目的spring需要保证线程下的数据库操作都使用同一个事务连接。那么当事务回滚的时候可以一次性回滚所有的数据库操作。if (TransactionSynchronizationManager.isSynchronizationActive()) {try {// Use same Connection for further JDBC actions within the transaction.// Thread-bound object will get removed by synchronization at transaction completion.// 在事务中使用同一个数据库连接。ConnectionHolder holderToUse conHolder;if (holderToUse null) {holderToUse new ConnectionHolder(con);}else {holderToUse.setConnection(con);}holderToUse.requested();TransactionSynchronizationManager.registerSynchronization(new ConnectionSynchronization(holderToUse, dataSource));holderToUse.setSynchronizedWithTransaction(true);if (holderToUse ! conHolder) {TransactionSynchronizationManager.bindResource(dataSource, holderToUse);}}catch (RuntimeException ex) {// Unexpected exception from external delegation call - close Connection and rethrow.releaseConnection(con, dataSource);throw ex;}}return con;}2.应用用户设定的输入参数 protected void applyStatementSettings(Statement stmt) throws SQLException {int fetchSize getFetchSize();if (fetchSize ! -1) {stmt.setFetchSize(fetchSize);}int maxRows getMaxRows();if (maxRows ! -1) {stmt.setMaxRows(maxRows);}DataSourceUtils.applyTimeout(stmt, getDataSource(), getQueryTimeout());}a: setFetchsize 最主要是为了减少网络交互次数设计的。访问 ResultSet 时如果它每次只从服务器上读取一行数据则会产生大量的开销。setFetchSize 的意思是当调用 rs.next 时ResultSet会一次性从服务器上取得多少行数据回来这样在下次 rs.next 时它可以直接从内存中获取数据而不需要网络交互提高了效率。这个设置可能会被某些 JDBC 驱动忽略而且设置过大也会造成内存的上升。 b: setMaxRows 将此 Statement对象生成的所有 ResulSet 对象可以包含的最大行数限制设置为给定数。 3. 调用回调函数处理 一些通用方法外的个性化处理,也就是 PreparedStatementCallback 类型的参数的dolnPreparedStatement 方法的回调。 4. 资源释放 数据库的连接释放并不是直接调用了 Connection 的APL中的.close 方法。考虑到存在事务的情况如果当前线程存在事务那么说明在当前线程中存在共用数据库连接这种情况下直接使用 ConnectionHolder 中的 released 方法进行连接数减一面不是真正的释放连接。 public static void doReleaseConnection(Nullable Connection con, Nullable DataSource dataSource) throws SQLException {if (con null) {return;}if (dataSource ! null) {// 当前线程存在事务的情况下说明存在共用数据库连接,直接使用 ConnectionHolder 中的released 方法进行连接数减一而不是真正的释放连接。ConnectionHolder conHolder (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);if (conHolder ! null connectionEquals(conHolder, con)) {// Its the transactional Connection: Dont close it.conHolder.released();return;}}// 直接使用Connection的API调用close方法释放连接doCloseConnection(con, dataSource);}Update中的回调函数 PreparedStatementCalback 作为一个接口其中只有一个函数 doInPreparedStatement这个函数是用于调用通用方法 execute 的时候无法处理的一些个性化处理方法在 update 中的函数实现 protected int update(final PreparedStatementCreator psc, Nullable final PreparedStatementSetter pss)throws DataAccessException {logger.debug(Executing prepared SQL update);// PreparedStatementCallback作为回调函数。execute 方法是最基础的操作而其他操作比如update、 query 等方法则是传人不同的 PreparedStatementCallback 参数来执行不同的逻辑return updateCount(execute(psc, ps - {try {if (pss ! null) {// ArgumentTypePreparedStatementSetter.setValue: 将参数赋值给对应的参数类型pss.setValues(ps);}// ps.executeUpdate(): JDBC-API的基本操作int rows ps.executeUpdate();if (logger.isTraceEnabled()) {logger.trace(SQL update affected rows rows);}return rows;}finally {if (pss instanceof ParameterDisposer) {((ParameterDisposer) pss).cleanupParameters();}}}, true));}其中用于真正执行 SQL 的 ps.executeUpdate 没有太多需要讲解的因为我们平时在直接使用JDBC 方式进行调用的时候会经常使用此方法。但是对于设置输人参数的函数 pss.set Values(ps)我们有必要去深人研究一下。在没有分析源码之前我们至少可以知道其功能不妨再回顾下 Spring 中使用 SOL 的执行过程直接使用 SQL 语句对应的参数对应参数的类型清晰明了这都归功于 Spring 为我们做了封裝而真正的 JDBC 调用其实非常繁琐你需要这么做 那么看看 Spring 是如何做到封装上面的操作呢首先所有的操作都是以 pss.setValues(ps)为入口的。还记得我们之前的分析路程吗这个pss 所代表的当前类正是 ArgPreparedStatementSetter。其中的 setValues 的相关源码分析此处略。 2.query 功能的实现 源码分析入口1(关键) 在之前的章节中我们介绍了 update 方法的功能实现那么在数据库操作中查找操作也是使用率非常高的函数同样我们也需要了解它的实现过程。使用方法如下 Overridepublic T ListT query(String sql, Object[] args, int[] argTypes, RowMapperT rowMapper) throws DataAccessException {return result(query(sql, args, argTypes, new RowMapperResultSetExtractor(rowMapper)));}OverrideNullablepublic T T query(String sql, Object[] args, int[] argTypes, ResultSetExtractorT rse) throws DataAccessException {// 与 update 方法中都同样使用了 newArgTypePreparedStatementSetter。return query(sql, newArgTypePreparedStatementSetter(args, argTypes), rse);}OverrideNullablepublic T T query(String sql, Nullable PreparedStatementSetter pss, ResultSetExtractorT rse) throws DataAccessException {return query(new SimplePreparedStatementCreator(sql), pss, rse);}核心代码如下 Nullablepublic T T query(PreparedStatementCreator psc, Nullable final PreparedStatementSetter pss, final ResultSetExtractorT rse)throws DataAccessException {Assert.notNull(rse, ResultSetExtractor must not be null);logger.debug(Executing prepared SQL query);// 此处会调用和update一样的execute方法return execute(psc, new PreparedStatementCallbackT() {OverrideNullablepublic T doInPreparedStatement(PreparedStatement ps) throws SQLException {ResultSet rs null;try {if (pss ! null) {// ArgumentTypePreparedStatementSetter.setValuepss.setValues(ps);}// ps.executeQuery():JDBC-API的基本操作rs ps.executeQuery();// rse.extractData(rsToUse)方法负责将结果进行封装并转换至 POJO rse 当前代表的类为RowMapperResultSetExtractor而在构造 RowMapperResultSetExtractor 的时候我们又将自定义的 rowMapper 设置了进去。return rse.extractData(rs);}finally {JdbcUtils.closeResultSet(rs);if (pss instanceof ParameterDisposer) {((ParameterDisposer) pss).cleanupParameters();}}}}, true);}可以看到整体套路与 update 差不多的只不过在回调类 PreparedStatementCallback 的中使用的是 ps.executeQuery()执行查询操作而且在返回方法上也做了一些额外的处理。 源码分析入口2(关键) 之前讲了 update 方法以及 query 方法使用这两个附数示例的 SQL 都是带有参数的也就是带有“”的那么还有另一种情况是不带有“?”的Spring 中使用的是另一种处理方式。例如 Listuser 1ist jdbcTemplate.query (selectfrom user, new UserRowMapper() );追踪进入 Overridepublic T ListT query(String sql, RowMapperT rowMapper) throws DataAccessException {return result(query(sql, new RowMapperResultSetExtractor(rowMapper)));}核心源码 /*** 功能描述与之前的 query 方法最大的不同是少了参数及参数类型的传递自然也少了 PreparedStatementSetter 类型的封装。* * param sql the SQL query to execute* param rse a callback that will extract all rows of results*/OverrideNullablepublic T T query(final String sql, final ResultSetExtractorT rse) throws DataAccessException {Assert.notNull(sql, SQL must not be null);Assert.notNull(rse, ResultSetExtractor must not be null);if (logger.isDebugEnabled()) {logger.debug(Executing SQL query [ sql ]);}/*** Callback to execute the query.*/class QueryStatementCallback implements StatementCallbackT, SqlProvider {OverrideNullablepublic T doInStatement(Statement stmt) throws SQLException {ResultSet rs null;try {rs stmt.executeQuery(sql);return rse.extractData(rs);}finally {JdbcUtils.closeResultSet(rs);}}Overridepublic String getSql() {return sql;}}// 既然少了 PreparedStatementSetter 类型的传入调用的 execute 方法自然也会有所改变了。return execute(new QueryStatementCallback(), true);}execute方法 /*** 功能描述这个 exexute 与之前的 execute 并无太大差别都是做一些常规的处理诸如获取连接、释连接等。* 但是有一个地方是不一样的就是 statement 的创建。这里直接使用connection 创建而带有参数的 SQL 使用的是 PreparedStatementCreator 类来创建的。一个是普通的 Statement,另一个是 PreparedStatement。** param T* throws DataAccessException*/Nullableprivate T T execute(StatementCallbackT action, boolean closeResources) throws DataAccessException {Assert.notNull(action, Callback object must not be null);Connection con DataSourceUtils.getConnection(obtainDataSource());Statement stmt null;try {stmt con.createStatement();applyStatementSettings(stmt);T result action.doInStatement(stmt);handleWarnings(stmt);return result;}catch (SQLException ex) {// Release Connection early, to avoid potential connection pool deadlock// in the case when the exception translator hasnt been initialized yet.String sql getSql(action);JdbcUtils.closeStatement(stmt);stmt null;DataSourceUtils.releaseConnection(con, getDataSource());con null;throw translateException(StatementCallback, sql, ex);}finally {if (closeResources) {JdbcUtils.closeStatement(stmt);DataSourceUtils.releaseConnection(con, getDataSource());}}}PreparedStatement 接口继承 Statement并与之在两方面有所不同 PreparedStatement 实例包含已编译的 SQL 语句这就是使语向“准备好”。包含于PreparedStatement 对象中的 SQL 语句可具有一个或多个IN 参数。IN 参数的值在 SQL语句创建时未被指定。相反的该语句为每个 IN 参数保留一个问号“2”作为占位符。每个问号的值必须在该语句执行之前通过适当的 setXXX 方法来提供。由于 PreparedStatement 对象已预编译过所以其执行速度要快于 Statement 对象。因此多次执行的 SQL 语句经常创建为 PreparedStatement 对象以提高效率。 3.queryForObject Spring 中不仅仅为我们提供了 query 方法还在此基础上做了封装提供了不同类型的 query方法。此处源码分析略。 总结 待补充。
http://www.hkea.cn/news/14298484/

相关文章:

  • 网站逻辑结构优化是指万家建设有限公司网站
  • 装饰网站建设优惠套餐企业网络营销分析报告
  • 上海市建设安全协会网站查询系统瘫网站开发方案 文档
  • 盘锦网站建设公司wap端网站建设
  • 商城网站建设资讯网站丢失了怎么办啊
  • 手机网站建站工作室网站怎么推广引流
  • 电商网站策划物流门户网站开发 报价
  • 设计企业品牌网站最大上传大小wordpress
  • 备案 非网站徐州峰华网架公司
  • 商城网站建设制作注册公司名字推荐
  • 永安城乡建设局网站wordpress 4.8中文版
  • 网站上推广游戏怎么做企业做网站大概需要多少钱
  • 在北京注册公司在哪个网站上网站开发基于百度地图
  • 2014网站推广方案手机怎么制作游戏
  • 公司建设网站有什么好处qq人脸解冻自助网站
  • 濮阳推广公司免费发布网站seo外链
  • 学做家常菜的网站有哪些怎么形容网站做的很好
  • 网上建设网站需要做的工作智能手机网站建设
  • 住房和城乡建设部网站办事大厅个人网站备案名称填写的注意事项
  • windows2008 iis 网站配置手机网站自适应分辨率
  • 一家专门做衣服的网站建盏金盏能不能喝茶
  • 网站服务网页托管网站
  • 怎样做企业手机网站建设广州个人网站制作
  • 佛山家具网站建设公司广州网站设计我选刻
  • 神木网站建设设计快速做网站费用
  • 网站微信建设运维培训班做视频网站空间要多大
  • 网站建设优化培训班软件开发前景分析
  • wordpress文章阅读更多按钮广东网站seo
  • 爱站网源码wordpress图片暗箱
  • 自己建设网站赚钱个人微信小程序怎么赚钱