热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

WEB03_Day02数据库连接池、SQL注入、JDBC批量操作、分页查询、JDBC获取新增数据的自增主键值

一、数据库连接池1.1定义:数据库连接池就是一个包含多个数据库连接对象的容器。1.2优势:每个连接对象都是需要进行创建,使用,关闭,销毁,如果反复的对于连接对象进行频繁创建

一、数据库连接池


1.1 定义:

  数据库连接池就是一个包含多个数据库连接对象的容器。


1.2 优势:



  • 每个连接对象都是需要进行创建,使用,关闭,销毁,如果反复的对于连接对象进行频繁创建和销毁操作,可能会导致程序出现内存泄漏和内存溢出的情况发生。



  • 需要创建多个连接对象,此时使用数据库连接池可以预先进行创建多个数据库连接对象,当使用的时候,可以直接从数据库连接池中进行获取,使用完毕以后,会进行归还,该操作可以让对象进行反复的使用,进行可以提高程序的执行效率,避免内存不足。




1.3 数据库连接池的使用



  • 在项目的 pom.xml 文件中导入数据库连接池的 jar 包




当前所使用的数据库连接池为 dbcp,后期还学学到阿里公司自研的数据库连接池 druid。DBCP(DataBase Collection Pool)


 
 <dependency>
     <groupId>commons-dbcpgroupId>
     <artifactId>commons-dbcpartifactId>
     <version>1.4version>
 dependency>


  • 重构 DBUtils 工具类,结合 DBCP数据库连接池进行使用



 package cn.tedu.dbcp;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.sql.Connection;
 import java.util.Properties;
 import org.apache.commons.dbcp.BasicDataSource;
 
 /**
  * JDBC连接MySQL工具类
  * @author Tedu
  *
  */
 public class DBUtils {
  //声明一个数据库连接池对象
  private static BasicDataSource ds;
 
  //将初始化数据库连接池对象的操作书写到静态块中
  static {
  //1.进行解析jdbc.properties配置文件,用户获取里面的连接参数
  //1.1获取输入流对象,用户读取项目的配置文件(磁盘->内存)
  InputStream in = DBUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
  //1.2使用Properties对象进行解析配置文件
  Properties p = new Properties();
  //1.3 加载配置文件的输入流
  try {
  p.load(in);
  } catch (IOException e) {
  e.printStackTrace();
  } catch (Exception e) {
  e.printStackTrace();
  }
 
  //2.使用解析得到的参数值进行获取连接对象
  String driver = p.getProperty("driver");
  String url = p.getProperty("url");
  String userName = p.getProperty("username");
  String password = p.getProperty("password");
 
  //创建数据库连接池对象,并将链接参数赋值给数据库连接池
  ds = new BasicDataSource();
  ds.setDriverClassName(driver);
  ds.setUrl(url);
  ds.setUsername(userName);
  ds.setPassword(password);
  //设置数据库连接池的初始数量
  ds.setInitialSize(5);
  //设置数据库连接池的最大活跃数量
  ds.setMaxActive(5);
  //设置最大的空闲连接数量
  ds.setMaxIdle(3);
 
  }
 
  /**
   * 静态方法,用户获取连接对象
  * @return 返回连接对象
  * @throws Exception
  */
  public static Connection getConn() throws Exception {
 
  //获取连接对象
  Connection conn = ds.getConnection();
  return conn;
 
  }
 
 }


  • 进行测试工具类中获取的连接对象



 package cn.tedu.dbcp;
 
 import java.sql.Connection;
 import java.sql.ResultSet;
 import java.sql.Statement;
 import org.junit.Test;
 
 public class JdbcDemo01 {
 
 
  @Test
  public void testSelect() {
  try (Connection conn = DBUtils.getConn();){
  Statement stat = conn.createStatement();
  String str = "SELECT deptno,dname,loc FROM dept";
  ResultSet rs = stat.executeQuery(str);
  while (rs.next()) {
  int deptno = rs.getInt(1);
  String dname = rs.getString(2);
  String loc = rs.getString(3);
  System.out.println("部门编号:" + deptno + ",部门名字:" + dname + ",地址:" + loc);
  }
 
  } catch (Exception e) {
  e.printStackTrace();
  }
  }
 
 
 }


  • 测试结果:



 部门编号:1,部门名字:神仙,地址:天庭
 部门编号:2,部门名字:妖怪,地址:盘丝洞
 部门编号:3,部门名字:普通人,地址:北京
 部门编号:4,部门名字:赛亚人,地址:外星球

二、SQL 注入


2.1 定义:

  SQL 注入就是指用户在可填写的内容中包含了可以进行运行的 sql 语句,如果包含了可以运行的 sql 语句有可能程序会被进行篡改。


2.2 SQL注入演示



  • 准备 user 数据表,表中存储用户的 id,用户名,密码。



 -- 如果存在 user 数据表,进行删除
 DROP TABLE IF EXISTS `user`;
 -- 创建 user 数据表
 CREATE TABLE `user`(
  id int AUTO_INCREMENT,
  username varchar(20) NOT NULL,
  password varchar(20) NOT NULL,
  PRIMARY KEY(id)
 )charset=utf8;
 -- 插入数据
 INSERT INTO `user` VALUES(null,'baojiaqi','12345678'),(null,'zhangyun','888888');
 -- 查询数据
 SELECT count(*) FROM `user` WHERE username='baojiaqi' AND password='12345678';


  • 通过 jdbc 连接 MySQL 数据库,进行查询某位用户是都可以进行登录。



 package cn.tedu.dbcp;
 
 import java.sql.Connection;
 import java.sql.ResultSet;
 import java.sql.Statement;
 import java.util.Scanner;
 import org.junit.Test;
 
 public class JdbcDemo02 {
 
  @Test
  public void testSQLInjection() {
  /*
  * 测试 SQL 注入风险演示
  */
  Scanner scan = new Scanner(System.in);
  //接收用户在控制台中输入的用户名和密码
  System.out.println("请输入用户名:");
  String userName = scan.nextLine();
  System.out.println("请输入密码:");
  String password = scan.nextLine();
 
  //连接 MySQL
  try (Connection conn = DBUtils.getConn();){
  //创建命令对象
  Statement stat = conn.createStatement();
  String sqlStr = "SELECT count(*) FROM user WHERE username='"
  +userName+"' AND password='"+password+"'";
  System.out.println("SQL语句:" + sqlStr);
  //''or'123'='123'
  //执行 sql,返回结果集
  ResultSet rs = stat.executeQuery(sqlStr);
  while (rs.next()) {
  int count = rs.getInt(1);
  if (count > 0) {
  System.out.println("登录成功");
  } else {
  System.out.println("登录失败");
  }
  }
 
  } catch (Exception e) {
 
  }
  scan.close();
 
  }
 
 
 }

 请输入用户名:
 baojiaqi
 请输入密码:
 12345678
 SQL语句:SELECT count(*) FROM user WHERE username='baojiaqi' AND password='12345678'
 登录成功

 请输入用户名:
 baojiaqi
 请输入密码:
 'or'123'='123
 SQL语句:SELECT count(*) FROM user WHERE username='baojiaqi' AND password=''or'123'='123'
 登录成功

2.3 解决 SQL 注入风险


2.3.1 PreparedStatement

  该接口的功能和 Statement 接口的功能大致相同,但是PreparedStatement接口在Statement接口的基础之上做了改进。


2.3.2 优点:



  • 防止 SQL 注入

    在创建 SQL 命令对象的时候,对 SQL 语句进行锁定,不会让用户进行字符串拼接,只会将用户输入的内容当成是一个数值。



  • 预编译机制:

    预先进行编译,当前写好的 SQL 进行提前编译,这样有助于提高运行的速度。



  • 代码可读性好

    在进行书写的时候并不需要进行对 SQL 做字符串拼接,而是进行 SQL 传值操作。




2.3.3 代码案例:

package cn.tedu.dbcp;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Scanner;
import org.junit.Test;
public class JdbcDemo03 {

@Test
public void testSQLInjection() {
/*
* 测试解决SQL注入风险
*/
Scanner scan = new Scanner(System.in);
//接收用户在控制台中输入的用户名和密码
System.out.println("请输入用户名:");
String userName = scan.nextLine();
System.out.println("请输入密码:");
String password = scan.nextLine();

//连接 MySQL
try (Connection cOnn= DBUtils.getConn();){

/*
* PreparedStatement接口在创建的时候需要指定后期要执行的 SQL 语句,
* 进行提前编译,在 SQL 语句中需要条件的位置使用占位符?进行站位
*/
String sqlStr = "SELECT count(*) FROM user WHERE username=? AND password=?";
//创建命令对象
PreparedStatement ps = conn.prepareStatement(sqlStr);
//对 SQL 中的占位符进行传值
ps.setString(1, userName);
ps.setString(2, password);

//执行 sql,返回结果集
ResultSet rs = ps.executeQuery();
while (rs.next()) {
int count = rs.getInt(1);
if (count > 0) {
System.out.println("登录成功");
} else {
System.out.println("登录失败");
}
}

} catch (Exception e) {

}
scan.close();

}


}


  • 测试结果:



请输入用户名:
baojiaqi
请输入密码:
'or'123'='123
登录失败

三、JDBC 批量操作


3.1 定义:

  使用 JDBC 技术进行多条 SQL 语句的一次执行操作,这个就是批量操作。


3.2 场景:

  假设项目的业务需求中需要一次性执行某条 SQL 时,需要执行多次,那么像之前的操作,每次执行 SQL 语句都需要进行创建命令对象,通过命令对象对 SQL 语句进行执行,往往整体的效率是比较低下的,所以说当前提供了可以进行批量操作的相关 API。

  当前命令对象中提供了 addBatch()方法和 executeBatch()方法,允许我们一次执行 SQL 语句时,可以进行批量的添加需要执行的 SQL 语句,然后统一的进行发送给数据库运行,从而可以进行提高执行效率。


3.3 使用 Statement 命令对象进行对数据的批量操作

package cn.tedu.batch;
import java.sql.Connection;
import java.sql.Statement;
import java.util.Arrays;
import org.junit.Test;
public class BatchOperation01 {

@Test
public void batch() {
//获取连接对象
try (Connection cOnn= DBUtils.getConn();){
//准备 sql
String sqlStr1 = "INSERT INTO user VALUES(null,'刘想','666')";
String sqlStr2 = "INSERT INTO user VALUES(null,'刘朝辉','888')";
String sqlStr3 = "INSERT INTO user VALUES(null,'孟沙','333')";
String sqlStr4 = "INSERT INTO user VALUES(null,'顾有鹏','555')";

/*
* addBatch()方法
* 一次性进行往命令对象中添加多条 SQL 语句
*
* executeBatch()方法
* 批量执行添加到命令对象中的一批 SQL 语句,
* 返回值是int[],数组中的每个元素表示每条 sql 语句在执行时受影响的行数
*/
Statement stat = conn.createStatement();

stat.addBatch(sqlStr1);
stat.addBatch(sqlStr2);
stat.addBatch(sqlStr3);
stat.addBatch(sqlStr4);

int[] nums = stat.executeBatch();
System.out.println(Arrays.toString(nums));


/*
* 以下的代码书写方案执行效率低下
*/
// Statement stat = conn.createStatement();
// stat.executeUpdate(sqlStr1);
// stat.executeUpdate(sqlStr2);
// stat.executeUpdate(sqlStr3);
// stat.executeUpdate(sqlStr4);


} catch (Exception e) {
e.printStackTrace();
}

}


}


  • 测试结果:



[1, 1, 1, 1]

3.4 使用 PreparedStatement 命令对象进行对数据的批量操作

package cn.tedu.batch;
import java.sql.Connection;
import java.sql.PreparedStatement;
import org.junit.Test;
public class BatchOperation02 {

@Test
public void testBath() {
//获取连接对象
try (Connection cOnn= DBUtils.getConn();){
//准备 sql
String sqlStr = "INSERT INTO user VALUES(null,?,?)";
//创建命令对象
PreparedStatement ps = conn.prepareStatement(sqlStr);

//循环向命令对象中进行添加需要执行的 sql 语句
for (int i = 1; i <= 130; i++) {
//向 sql 中的占位符进行传值
ps.setString(1, "user" + i);
ps.setString(2, "password" + i);
//将 sql 语句批量添加到命令对象
ps.addBatch();
/*
* 将需要执行的 sql 语句批量发送给数据库,
* 原因是为了减轻数据库的压力,防止内存占用过大。
*/
if (i % 20 == 0) {
ps.executeBatch();
}
}
//防止有未发送给数据库执行的 sql 语句,再次提交
ps.executeBatch();

} catch (Exception e) {
e.printStackTrace();
}
}

}

四、分页查询


4.1 定义:

  当查询的数据信息较多时,会在不同的网页中进行展示,称之为分页查询。


4.2 优点:



  • 可以节约用户的流量

    按照页数进行查询数据,未进行访问的页面并不会进行消耗用户的流量



  • 提升用户体验感

    当将所有的数据都在一页中进行展示,用户往往不需要全部都查看,只需要查看部分信息即可得到自己想要的答案。



  • 节约服务器资源

    并不需要全部查询出数据信息,进而可以节约服务的资源




4.3 Java 代码实现分页

package cn.tedu.page;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Scanner;
import org.junit.Test;
public class JdbcPage {

@Test
public void page() {
/*
* 希望根据用户在控制台中输入页号和每页显示的数据条数进行查询
* 需求:每页显示 5 条数据, 查询第 3 页的数据
* 第一页 跳过数据条数 每页显示数据条数
* 1 0 5
* 2 1*5 5
* 3 2*5 5
* 4 3*5 5
* n (n-1)*5 5
*/
Scanner scan = new Scanner(System.in);
System.out.println("请输入每页显示的数据条数:");
int size = scan.nextInt();
System.out.println("请输入查询数据的页号:");
int pageNum = scan.nextInt();

try (Connection cOnn= DBUtils.getConn();){
String sqlStr = "SELECT id,username,password FROM user limit ?,?";
PreparedStatement ps = conn.prepareStatement(sqlStr);
int count = (pageNum-1)*size;
ps.setInt(1, count);
ps.setInt(2, size);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
int id = rs.getInt(1);
String username = rs.getString(2);
String password = rs.getString(3);
System.out.println(id + "," + username + "," + password);

}

} catch (Exception e) {
e.printStackTrace();
}
scan.close();


}


}


  • 测试结果:



请输入每页显示的数据条数:
5
请输入查询数据的页号:
3
11,user5,password5
12,user6,password6
13,user7,password7
14,user8,password8
15,user9,password9


五、JDBC 获取新增数据的自增主键值


5.1 获取新增数据的主键值

业务:当向 user 表中插入一条数据以后,如果在没有进行书写 SELECT 查询语句的时候如何获取新增数据的主键值?

package cn.tedu.primary;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
import org.junit.Test;
public class JdbcPrimary01 {

@Test
public void getPrimaryKey() {

/*
* 通过控制台输入需要进行新增的用户名和密码
*/
Scanner scan = new Scanner(System.in);
System.out.println("请输入用户名:");
String name = scan.nextLine();
System.out.println("请输入密码:");
String password = scan.nextLine();

try (Connection cOnn= DBUtils.getConn();){
String sqlStr = "INSERT INTO user VALUES(null,?,?)";
/*
* 在使用prepareStatement方法的时候,选择两个参数的重载方法,
* 参数一:进行预编译的 sql 语句
* 参数二:表示设定需要查询新增数据生成的主键值
*/
PreparedStatement ps = conn.prepareStatement(sqlStr,Statement.RETURN_GENERATED_KEYS);
ps.setString(1,name);
ps.setString(2, password);

ps.executeUpdate();

/*
* 通过命令对象调用getGeneratedKeys()方法获取刚刚新增数据的主键值,返回结果是 ResultSet
* 当前可以获取新增数据主键值的前提一定是在创建命令对象的时候设置了Statement.RETURN_GENERATED_KEYS常量
*/
ResultSet rs = ps.getGeneratedKeys();
while (rs.next()) {
//因为结果对象中只有一个值,就是刚刚进行新增数据的主键
int id = rs.getInt(1);
System.out.println("新增数据的主键为:" + id);
}

} catch (Exception e) {
e.printStackTrace();
}

scan.close();
}

}

5.2 案例

  业务需求:当前准备两张数据表,分别为球队表和球员表,然后编写一个Java 程序,让用户可以注册球队和球员的信息,当前需要确保新注册的球员能够对应已有的球队。

-- 球队表
CREATE TABLE team(
team_id int AUTO_INCREMENT,
team_name varchar(20),
PRIMARY KEY(team_id)
)charset=utf8;
-- 向球队表新增数据
INSERT INTO team VALUES(null,'中国队');
INSERT INTO team VALUES(null,'美国队');
INSERT INTO team VALUES(null,'西班牙队');
-- 球员表
CREATE TABLE player(
player_id int AUTO_INCREMENT,
player_name varchar(20),
palyer_team_id int,
PRIMARY KEY(player_id)
)charset=utf8;
-- 向球员表中新增数据
INSERT INTO player VALUES(null,'易建联',1);
INSERT INTO player VALUES(null,'杜兰特',2);
INSERT INTO player VALUES(null,'加索尔',3);

-- 新增球员成功,但是确实数据的完整性,并没有id为的4的球队
INSERT INTO player VALUES(null,'包佳奇',4);
-- 删除缺失完整性的数据
DELETE FROM player WHERE player_id=4;
-- 在球员表中添加外键,为了确保数据的完整性
ALTER TABLE player ADD FOREIGN KEY(palyer_team_id) REFERENCES team(team_id);
-- 添加外键以后再次进行执行新增球员表中的球队信息为 4 的数据,插入失败
INSERT INTO player VALUES(null,'包佳奇',4);
-- 报错结果
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`newdb3`.`player`, CONSTRAINT `player_ibfk_1` FOREIGN KEY (`palyer_team_id`) REFERENCES `team` (`team_id`))



























 主键外键
定义唯一的表示,非空且唯一一张表的外键是另一张表的主键,外键允许是空值,也可以是重复的
作用用来保证数据的完整性用来和其他表之间建立关系
个数1 张数据表只能设置 1 个1 张数据表可以有多个外键

5.3 作业:

  业务:当前已经准备了球员表和球队表,希望用户在控台中输入需要新增的球员名字,和新增球队的名字,当前球员的数据中,针对于所在球队这列的值是新增球队的主键值,最终完整球员和球队信息的新增。

package cn.tedu.primary;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
/**
* 球员和球队建立外键关系
* 1.新增球队信息
* 2.获取新增球队的主键值
* 3.新增球员信息
* 将新增球队的id作为新增球员的一个外键字段的值
* @author Tedu
*
*/
public class TeamPlayerDemo {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("请输入球队名称:");
String team = scan.nextLine();
System.out.println("请输入球员姓名:");
String player = scan.nextLine();

try (Connection cOnn= DBUtils.getConn();){
//准备sql
String sql1 = "INSERT INTO team VALUES(null,?)";
//创建命令对象
PreparedStatement ps =
conn.prepareStatement(sql1, Statement.RETURN_GENERATED_KEYS);
//向sql中占位符赋值
ps.setString(1, team);
//执行插入球队sql语句
ps.executeUpdate();
//获取新增球队数据的主键值
ResultSet rs = ps.getGeneratedKeys();
while (rs.next()) {
//取出新增球队主键值
int teamId = rs.getInt(1);
String sql2 = "INSERT INTO player VALUES(null,?,?)";
//创建命令对象
PreparedStatement ps2 =
conn.prepareStatement(sql2);
ps2.setString(1, player);
ps2.setInt(2, teamId);
ps2.executeUpdate();
System.out.println("新增完毕");
}


} catch (Exception e) {
e.printStackTrace();
}
scan.close();

}
}

 



推荐阅读
  • 在基于.NET框架的分层架构实践中,为了实现各层之间的松散耦合,本文详细探讨了依赖注入(DI)和控制反转(IoC)容器的设计与实现。通过合理的依赖管理和对象创建,确保了各层之间的单向调用关系,从而提高了系统的可维护性和扩展性。此外,文章还介绍了几种常见的IoC容器实现方式及其应用场景,为开发者提供了实用的参考。 ... [详细]
  • Spring框架的核心组件与架构解析 ... [详细]
  • 本文作为探讨PHP依赖注入容器系列文章的开篇,将首先通过具体示例详细阐述依赖注入的基本概念及其重要性,为后续深入解析容器的实现奠定基础。 ... [详细]
  • Spring框架入门指南:专为新手打造的详细学习笔记
    Spring框架是Java Web开发中广泛应用的轻量级应用框架,以其卓越的功能和出色的性能赢得了广大开发者的青睐。本文为初学者提供了详尽的学习指南,涵盖基础概念、核心组件及实际应用案例,帮助新手快速掌握Spring框架的核心技术与实践技巧。 ... [详细]
  • SQLmap自动化注入工具命令详解(第28-29天 实战演练)
    SQL注入工具如SQLMap等在网络安全测试中广泛应用。SQLMap是一款开源的自动化SQL注入工具,支持12种不同的数据库,具体支持的数据库类型可在其插件目录中查看。作为当前最强大的注入工具之一,SQLMap在实际应用中具有极高的效率和准确性。 ... [详细]
  • 如何有效防御网站中的SQL注入攻击
    本期文章将深入探讨网站如何有效防御SQL注入攻击。我们将从技术层面详细解析防范措施,并结合实际案例进行阐述,旨在帮助读者全面了解并掌握有效的防护策略。希望本文能为您的网络安全提供有益参考。 ... [详细]
  • 在Java分层设计模式中,典型的三层架构(3-tier application)将业务应用细分为表现层(UI)、业务逻辑层(BLL)和数据访问层(DAL)。这种分层结构不仅有助于提高代码的可维护性和可扩展性,还能有效分离关注点,使各层职责更加明确。通过合理的设计和实现,三层架构能够显著提升系统的整体性能和稳定性。 ... [详细]
  • 提升 Kubernetes 集群管理效率的七大专业工具
    Kubernetes 在云原生环境中的应用日益广泛,然而集群管理的复杂性也随之增加。为了提高管理效率,本文推荐了七款专业工具,这些工具不仅能够简化日常操作,还能提升系统的稳定性和安全性。从自动化部署到监控和故障排查,这些工具覆盖了集群管理的各个方面,帮助管理员更好地应对挑战。 ... [详细]
  • 提升Android开发效率:Clean Code的最佳实践与应用
    在Android开发中,提高代码质量和开发效率是至关重要的。本文介绍了如何通过Clean Code的最佳实践来优化Android应用的开发流程。以SQLite数据库操作为例,详细探讨了如何编写高效、可维护的SQL查询语句,并将其结果封装为Java对象。通过遵循这些最佳实践,开发者可以显著提升代码的可读性和可维护性,从而加快开发速度并减少错误。 ... [详细]
  • PHP自学必备:从零开始的准备工作与工具选择 ... [详细]
  • 作为软件工程专业的学生,我深知课堂上教师讲解速度之快,很多时候需要课后自行消化和巩固。因此,撰写这篇Java Web开发入门教程,旨在帮助初学者更好地理解和掌握基础知识。通过详细记录学习过程,希望能为更多像我一样在基础方面还有待提升的学员提供有益的参考。 ... [详细]
  • 本文详细介绍了如何安全地手动卸载Exchange Server 2003,以确保系统的稳定性和数据的完整性。根据微软官方支持文档(https://support.microsoft.com/kb833396/zh-cn),在进行卸载操作前,需要特别注意备份重要数据,并遵循一系列严格的步骤,以避免对现有网络环境造成不利影响。此外,文章还提供了详细的故障排除指南,帮助管理员在遇到问题时能够迅速解决,确保整个卸载过程顺利进行。 ... [详细]
  • 本项目在Java Maven框架下,利用POI库实现了Excel数据的高效导入与导出功能。通过优化数据处理流程,提升了数据操作的性能和稳定性。项目已发布至GitHub,当前最新版本为0.0.5。该项目不仅适用于小型应用,也可扩展用于大型企业级系统,提供了灵活的数据管理解决方案。GitHub地址:https://github.com/83945105/holygrail,Maven坐标:`com.github.83945105:holygrail:0.0.5`。 ... [详细]
  • 掌握PHP框架开发与应用的核心知识点:构建高效PHP框架所需的技术与能力综述
    掌握PHP框架开发与应用的核心知识点对于构建高效PHP框架至关重要。本文综述了开发PHP框架所需的关键技术和能力,包括但不限于对PHP语言的深入理解、设计模式的应用、数据库操作、安全性措施以及性能优化等方面。对于初学者而言,熟悉主流框架如Laravel、Symfony等的实际应用场景,有助于更好地理解和掌握自定义框架开发的精髓。 ... [详细]
  • 本文探讨了如何在C#应用程序中通过选择ComboBox项从MySQL数据库中检索数据值。具体介绍了在事件处理方法 `comboBox2_SelectedIndexChanged` 中可能出现的常见错误,并提供了详细的解决方案和优化建议,以确保数据能够正确且高效地从数据库中读取并显示在界面上。此外,还讨论了连接字符串的配置、SQL查询语句的编写以及异常处理的最佳实践,帮助开发者避免常见的陷阱并提高代码的健壮性。 ... [详细]
author-avatar
虎爷在江湖
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有