JNDI连接数据库

本文涉及的产品
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
云数据库 RDS SQL Server,独享型 2核4GB
云数据库 RDS MySQL,集群版 2核4GB 100GB
推荐场景:
搭建个人博客
简介: 一、JNDI数据库连接通用数据访问层(JNDIDBManager) 代码下: package com.myphome.dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; impor

一、JNDI数据库连接通用数据访问层(JNDIDBManager)

代码下:

package com.myphome.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

/**
 * JNDI数据库连接通用数据访问层
 * */
public class JNDIDBManager {
 //mySql连接固定参数和数据源名称字符串(分为两部分"java:comp/env"为JavaEE默认路径,"jdbc/blog"为DataSource名)
 private static final String MYSQL_DATASOURCE_STRING="java:comp/env/jdbc/blog";
 //sqlserver连接固定参数和数据源名称字符串
 private static final String SQLSERVER_DATASOURCE_STRING="java:comp/env/googlesnack";
 //oracle连接固定参数和数据源名称字符串
 private static final String ORACLE_DATASOURCE_STRING="java:comp/env/users";
 
 //使用单例模式来保存数据库对象
 private static ThreadLocal<Connection> tlconn=new ThreadLocal<Connection>();
 /**
  * 获取JNDI连接数据库对象
  * @throws NamingException
  * @throws SQLException
  * */
 public Connection getConnection() throws NamingException, SQLException{
 /*
  * ThreadLocal类可以保存一个对象,只能保存一个, 调用get方法得到保存的对象, 调用set方法向ThreadLocal中保存对象
  * 调用remove()方法,将ThreadLocal中的对象移除
  * 如果ThreadLocal中保存了连接对象,就从ThreadLocal中获取连接对象
  * 如果ThreadLocal没有保存连接对象,就从连接池中获取一个连接对象,并把该连接对象保存到ThreadLocal中
  */
  //从ThreadLocal获取Connection对象
  Connection conn=tlconn.get();
  //如果ThreadLocal中存在连接对象,则返回连接对象
  if(conn!=null){
   return conn;
  }else{

  //否则从连接池中获取一个连接对象,然后将连接对象放到ThreadLocal中,并返回该连接对象
   //数据源DataSource由Tomcat提供,不能在程序中创建实例,并使用JNDI获得DataSource引用
   /*
    *JNDI(Java Naming and Directory Interface,Java命名和目录接口)是一组在Java应用中访问命名和目录服务的API
    *javax.namming.Context接口的lookup()方法
    */
   Context context=new InitialContext();
   /*
    *javax.sql.DataSource接口负责建立与数据库的连接
    *从Tomcat的数据源获得连接
    *把连接保存在连接池中
    */
   //mysql
   DataSource ds=(DataSource) context.lookup(MYSQL_DATASOURCE_STRING);
   //sqlserver
//   DataSource ds=(DataSource) context.lookup(SQLSERVER_DATASOURCE_STRING);

//   //oracle
//   DataSource ds=(DataSource) context.lookup(ORACLE_DATASOURCE_STRING);
   //获取连接对象
   conn=ds.getConnection();
   //将数据库连接对象放入到ThreadLocal中
   tlconn.set(conn);
   return conn;
  }
 }

 /**
  * 从ThreadLocal中移除连接对象,以免线程池误操作本地变量
  * */
 public void removeConnection()throws Exception {
  tlconn.remove();//将ThreadLocal中保存的连接对象移除,移除后tl.get()方法得到的结果是null
 }
 /**
  * 为sql语句占位符赋值
  * */
 private void operateParameters(PreparedStatement pstmt,Object ... args) throws SQLException {
    if (args != null && args.length > 0) {
        for (int i = 0; i < args.length; i++) {
            pstmt.setObject(i + 1, args[i]);
        }
   }
 }
 /**
  * 将结果集转换为实体对象的接口
  * Mapper接口用于规定将数据行转换为entity的方法,以Mapper结尾的类(如:ArticleMapper)是该接口的子类
  * Mapper子类用于将rs指向的数据行转换为指定的entity对象
  * */
 public static interface RowMapper<T> {
  public T rowMapper(ResultSet rs);
 }

 /**
  * 数据库查询方法
  * @return list<T>
  * 第二个参数rowmapper:明确由哪个类负责将数据行转换为entity对象
  * 第一个参数:sql语句
  * 第三个参数:sql语句参数的值
  * */
 public <T> List<T> executeQuery(String sql, RowMapper mapper,Object ... values) throws Exception{
  List list = new ArrayList<T>();
  Connection conn = null;
  PreparedStatement pstmt = null;
  ResultSet rs = null;
  try {
   conn = getConnection();
   pstmt = conn.prepareStatement(sql);
   operateParameters(pstmt, values);
   rs = pstmt.executeQuery();

   
   //将结果集一条记录转换为实体对象,并添加到集合中
   while (rs.next()) {
    T obj = (T) mapper.rowMapper(rs);
    list.add(obj);
   }
  } catch (SQLException e) {
   e.printStackTrace();
   throw new Exception("执行数据查询时,失败");
  } finally {
   //关闭rs
   closeResultSet(rs);
   //关闭pstmt
   closeStatement(pstmt);
   //注意,rs和pstmt是DBManager关闭的,conn是有调用DBManager类关闭的
  }
  return list;
 }

 /**
  * 数据库更新数据方法(添加、修改、删除)
  * @return int
  * */
 public int executeUpdate(String sql, Object...args) throws Exception {
  PreparedStatement pstmt = null;
  int rowCount = 0;
  Connection conn = getConnection();
  try {
   pstmt = conn.prepareStatement(sql);
   operateParameters(pstmt, args);
   rowCount = pstmt.executeUpdate();
  } catch (SQLException e) {
   e.printStackTrace();
   throw new Exception("更新数据失败");
  } finally {
   closeStatement(pstmt);
  }
  return rowCount;
 }
 /**
  * 执行聚合函数查询(求总和)
  * */
 public int executeScalar(String sql,Object ...values){
  Connection conn = null;
  PreparedStatement pstmt = null;
  ResultSet rs = null;
  try {
   conn = getConnection();
   pstmt = conn.prepareStatement(sql);
   operateParameters(pstmt, values);
   rs = pstmt.executeQuery();
   if(rs.next()){
    return rs.getInt(1);
   }
   return 0;
  }catch (Exception e) {
   return 0;
  }finally{
   closeResultSet(rs);
   closeStatement(pstmt);
  }
 }
 /**
  * 关闭连接
  *
  * @param dbConnection
  *            Connection
  */
 public void closeConnection() {
  try {
   Connection conn = tlconn.get();
   if (conn != null && (!conn.isClosed())) {
    //关闭连接对象
    conn.close();
    conn = null;

    //将连接对象从tl中移除
    tlconn.remove();
   }
  } catch (SQLException e) {
   e.printStackTrace();
  }

 }
 /**
  * 关闭结果集
  */
 public void closeResultSet(ResultSet rs) {
  try {
   if (rs != null) {
    rs.close();
    rs = null;
   }
  } catch (SQLException e) {
   e.printStackTrace();
  }
 }

 /**
  * 关闭语句
  */
 public void closeStatement(PreparedStatement pstmt) {
  try {
   if (pstmt != null) {
    pstmt.close();
    pstmt = null;
   }
  } catch (SQLException e) {
   e.printStackTrace();
  }
 }
 /**
  * 开始事务
  * */
 public void setAutoCommit()throws Exception {
  try {
   getConnection();
   
   //开始事务
   tlconn.get().setAutoCommit(false);
  } catch (SQLException e) {
   e.printStackTrace();
   throw new Exception("开始事务时,出现错误");
  }
 }
 /**
  * 提交事务
  * */
 public void commit() throws Exception {
  try {
   //提交事务
   tlconn.get().commit();
  } catch (SQLException e) {
   e.printStackTrace();
   throw new Exception("事务提交失败");
  }
 }
 /**
  * 回滚事务
  * */
 public void rollback() throws Exception{
  try {
   //回滚事务
   tlconn.get().rollback();
  } catch (SQLException e) {
   e.printStackTrace();
   throw new Exception("事务回滚失败");
  }
 }
}


二、将结果集rs指向的数据当前一行记录转换为指定的entity对象的mapper类(如:FoodMapper)

package com.myphome.mapper;
import java.sql.ResultSet;

import com.myphome.dao.JNDIDBManager;
import com.myphome.entity.Food;

/**
 *FoodMapper用于将界面需要的数据查询出来,然后将rs指向的一条记录转换为Food实体类
 */
public class FoodMapper implements JNDIDBManager.RowMapper<Food> {

 public Food rowMapper(ResultSet rs) {
  Food food = null;
  try {
   food = new Food();
   food.setAgio(rs.getDouble("agio"));
   food.setCharacteristics(rs.getString("characteristics"));
   food.setCuisine(null)
;//把其他实体类作为此对象属性赋值(用第二个sql查询赋值,即sql嵌套)
   food.setCuisineId(rs.getInt("cuisineId"));
   food.setEatery(null);
   food.setEateryId(rs.getInt("eateryId"));
   food.setFingredient(rs.getString("fingredient"));
   food.setId(rs.getInt("id"));
   food.setImg(rs.getString("img"));
   food.setIntegral(rs.getInt("integral"));
   food.setName(rs.getString("name"));
   food.setPrice(rs.getDouble("price"));
   food.setRemark(rs.getString("remark"));
  } catch (Exception e) {
   food =null;
   e.printStackTrace();
  }
  return food;
 }
}
三、Food实体类

package com.myphome.entity;

import java.io.Serializable;

/**
 * 菜品
 */
public class Food implements Serializable{
 private int id; //食物的主键
 private String name;//食物的名称
 private String fingredient;//食物的配料
 private double price;//食物的价格
 private double agio;//食物的折扣
 private String remark;//食物的简介
 private String characteristics;//食物的特色
 private String img;//食物的图片
 private int integral;//购买食物所送积分
 
 private int cuisineId;//食物所属菜系的id
 private int eateryId;//食物所属餐馆的id
 
 //对象属性,菜系类
 private Cuisine cuisine;
 //对象属性,菜馆类
 private Eatery eatery;
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 /**
  * 获取配料
  * */
 public String getFingredient() {
  return fingredient;
 }
 
 /**
  * 设置配料
  * */
 public void setFingredient(String fingredient) {
  this.fingredient = fingredient;
 }
 public double getPrice() {
  return price;
 }
 public void setPrice(double price) {
  this.price = price;
 }
 public double getAgio() {
  return agio;
 }
 public void setAgio(double agio) {
  this.agio = agio;
 }
 public String getRemark() {
  return remark;
 }
 public void setRemark(String remark) {
  this.remark = remark;
 }
 /**
  * 获取特色
  * */
 public String getCharacteristics() {
  return characteristics;
 }
 /**
  * 设置特色
  * */
 public void setCharacteristics(String characteristics) {
  this.characteristics = characteristics;
 }
 public String getImg() {
  return img;
 }
 public void setImg(String img) {
  this.img = img;
 }
 /**
  * 获取积分
  * */
 public int getIntegral() {
  return integral;
 }
 
 /**
  * 设置积分
  * */
 public void setIntegral(int integral) {
  this.integral = integral;
 }
 public int getCuisineId() {
  return cuisineId;
 }
 public void setCuisineId(int cuisineId) {
  this.cuisineId = cuisineId;
 }
 public int getEateryId() {
  return eateryId;
 }
 public void setEateryId(int eateryId) {
  this.eateryId = eateryId;
 }
 public Cuisine getCuisine() {
  return cuisine;
 }
 public void setCuisine(Cuisine cuisine) {
  this.cuisine = cuisine;
 }
 public Eatery getEatery() {
  return eatery;
 }
 public void setEatery(Eatery eatery) {
  this.eatery = eatery;
 }
}
四、JNDI的配置步骤:

 

1.Tomcatconf/context.xml中的配置:

<Context>
 <!--**JNDI  DataSource数据源tomcat下配置**-->
 <!--sqlserver-->
 <Resource name="googlesnack" auth="Container" type="javax.sql.DataSource"
    maxActive="100" maxIdle="30" maxWait="10000"
    username="sa" password="sa" driverClassName="com.microsoft.jdbc.sqlserver.SQLServerDriver"
    url="jdbc:sqlserver://localhost:1433;DatabaseName=google_snack"/>
 <!--mysql-->
 <Resource name="jdbc/blog" auth="Container" type="javax.sql.DataSource"
  maxActive="100" maxIdle="30" maxWait="60000"
  username="root" password="root" driverClassName="org.gjt.mm.mysql.Driver"
  url="jdbc:mysql://localhost:3306/blog"/>
 <!--oracle-->
 <Resource name="users" auth="Container" type="javax.sql.DataSource"
  maxActive="100" maxIdle="30" maxWait="60000"
  username="kekeai" password="kekeai123" driverClassName="oracle.jdbc.driver.OracleDriver"
  url="jdbc:oracle:thin:@localhost:1521:orcl"/>
</Context>

  注:

2.加入数据库驱动文件:

把数据库驱动的.jar文件,加入到Tomcat下lib中。
 
3.(可省略) 应用程序的 web.xml 文件的配置,web.xml中配置<resource-ref>
 

注:如果用junit测试,将报错:

javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initial

解决:用web项目形式测试,则成功!

 

 

//tomcat下context.xml 中有汉字将报编码错误。

//界面提交using POST method,则:this.dopost(request,response);

 

 

 

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
11天前
|
JavaScript 关系型数据库 API
Nest.js 实战 (二):如何使用 Prisma 和连接 PostgreSQL 数据库
这篇文章介绍了什么是Prisma以及如何在Node.js和TypeScript后端应用中使用它。Prisma是一个开源的下一代ORM,包含PrismaClient、PrismaMigrate、PrismaStudio等部分。文章详细叙述了安装PrismaCLI和依赖包、初始化Prisma、连接数据库、定义Prisma模型、创建Prisma模块的过程,并对比了Prisma和Sequelize在Nest.js中的使用体验,认为Prisma更加便捷高效,没有繁琐的配置。
Nest.js 实战 (二):如何使用 Prisma 和连接 PostgreSQL 数据库
|
2天前
|
SQL 关系型数据库 MySQL
如何在PHP中连接到数据库?
在PHP中连接MySQL数据库常用的方法是MySQLi与PDO。MySQLi专为MySQL设计,支持面向对象及过程化编程,并提供预处理语句防止SQL注入。
|
9天前
|
缓存 分布式计算 DataWorks
DataWorks操作报错合集之连接数据库时出现了通信链接失败的报错,该如何解决
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
|
9天前
|
SQL DataWorks Java
DataWorks操作报错合集之在与某个数据库服务器建立或保持通信连接时遇到报错,该如何解决
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
|
17天前
|
ARouter 关系型数据库 MySQL
Django项目同时连接多个不同的数据库(7)
【7月更文挑战第7天】在Django项目中配置连接多个数据库,你需要: 1. 在`settings.py`中配置多个数据库, 2. 在`settings.py`内设置数据库路由,指定每个应用使用的数据库,
34 2
|
21天前
|
前端开发 NoSQL 数据库
部署常用的流程,可以用后端,连接宝塔,将IP地址修改好,本地只要连接好了,在本地上前后端跑起来,前端能够跑起来,改好了config.js资料,后端修改好数据库和连接redis,本地上跑成功了,再改
部署常用的流程,可以用后端,连接宝塔,将IP地址修改好,本地只要连接好了,在本地上前后端跑起来,前端能够跑起来,改好了config.js资料,后端修改好数据库和连接redis,本地上跑成功了,再改
|
21天前
|
弹性计算 NoSQL 网络安全
软件开发常见之云数据库Redis连接不上如何解决,修改配置后,需要重启下redis服务,配置才能生效呢,是重启,而不是重载配置,最后导致的问题是点击了的重启,配置修改了之后必须点击重启,而不是修改
软件开发常见之云数据库Redis连接不上如何解决,修改配置后,需要重启下redis服务,配置才能生效呢,是重启,而不是重载配置,最后导致的问题是点击了的重启,配置修改了之后必须点击重启,而不是修改
|
2天前
|
Oracle 关系型数据库 MySQL
入职必会-开发环境搭建17-IDEA连接数据库
IntelliJ IDEA集成了众多插件,方便开发者使用,使用IDEA自带的Database模块就可以很方便的配置、连接数据库,在 IntelliJ IDEA 中连接数据库,可以按照以下步骤进行操作。
|
26天前
|
Java 关系型数据库 MySQL
使用MySQL JDBC连接数据库
使用MySQL JDBC连接数据库
|
5天前
|
SQL 数据库 数据安全/隐私保护
为什么程序连接不同的数据库要使用不同的账号
为什么程序连接不同的数据库要使用不同的账号