JDBC连接MySQL(干货)

本文详细介绍了Java使用JDBC连接MySQL数据库的过程,包括JDBC的概念、使用JDBC的原因、执行SQL的方法、配置文件解析、数据库连接池DBCP的使用、SQL注入风险的防范、批量操作、事务处理以及获取元数据。还提供了JDBC练习源代码供读者实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JAVA连接JDBC操作数据库

什么是JDBC

Java DataBase Connectivity,Java数据库连接,jdbc实际是java中的一套和数据库交互的API(application program interface 应用程序编程接口)

为什么使用JDBC

因为Java程序员需要连接多种数据库,为了避免每一个数据库都学习一套新的API,sun公司提出了一个JDBC接口,各个数据库厂商根据此接口写实现类(驱动),这样java程序员只需要掌握JDBC接口中的一套方法,就可以访问任何数据库。
导包: import java.sql.*

如何使用JDBC
外网访问:https://mvnrepository.com/
1. 从maven网站上搜索mysql 找到5.1.6版本的坐标,把坐标复制到工程的pom.xml文件中 ,在pom.xml文件源码里面project标签内部 添加<dependecies>标签,把复制的内容粘贴到里面 ,保存在工程中出现奶瓶即可、
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<version>5.1.6</version>
	</dependency>
2. 创建Demo01.java 在main方法中写以下代码:
	//1.注册驱动
	Class.forName("com.mysql.jdbc.Driver");
	//2. 获取连接对象
	Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/newdb3","root","root");
	//System.out.println(conn);
	//3.创建执行SQL语句的对象
	Statement stat = conn.createStatement();
	//4.执行SQL
	String sql = "create table if not exists jdbct1(id int primary key auto_increment,name varchar(10))";
	stat.execute(sql); 
	System.out.println("执行完成");
	//5.关闭资源,先打开的资源后关闭
	stat.close();
	conn.close(); 
执行SQL的方法
execute(sql): 此方法可以执行任意SQL,但是推荐执行DDL(create drop alter truncate) ,方法的返回值为布尔值,返回值代表是否有结果集,'true':有结果集,'false':没有结果集
executeUpdate(sql): (DML)此方法执行增删改的SQL,方法返回值为int类型,代表生效(ok)行数
executeQuery(sql):	此方法执行select查询的SQL,返回值为ResultSet结果集
解析配置文件
配置文件位置:
	src/main/resources
配置文件名:jdbc.properties
		driver=com.mysql.jdbc.Driver
		url=jdbc:mysql://localhost:3306/newdb3
		username=root
		password=123456
		initialSize=2
		maxActive=10
解析文件:
	/**
	 * 解析Properties后缀文件,获取对应的信息
	* properties后缀文件是以键值对方式存储信息
	 */
	//创建属性对象
	Properties prop= new Properties();
	//得到文件输入流'Demo05表示类名'
	InputStream ips=Demo05.class.getClassLoader().getResourceAsStream("jdbc.properties");
	//把流交给属性对象
	prop.load(ips);
	//获取数据,只能获取到字符串类型的数据
	String name = prop.getProperty("name");
	String age = prop.getProperty("age");
	System.out.println(name+": "+age);	
	//注册驱动以及设置连接池
ResultSet
	获取数据的方式有两种:
		1、通过查询到的字段名称获取数据   rs.getString("ename");
		2、通过查询到的字段位置获取数据   rs.getString(2);
	数据库类型和java类型对比:
		MySQL               	java
		int 		       		getInt()
		varchar		       		getString()
		float/double       		getFloat()/getDouble()
		datetime/timestamp 		getDate()
数据库连接池DBCP
DataBase Connection Pool:数据库连接池
	为什么使用:如果没有数据库连接池,每次业务都需要和数据库建立一次连接,用完之后断开,如果有1万次业务请求则有1万次连接的开和关,频繁开关连接,浪费资源,使用数据库连接池可以将连接重用,避免资源的浪费
如何使用数据库连接池
	1. 下载jar包: 从maven服务器中搜索 dbcp
		<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
			<version>1.4</version>
		</dependency>
	2. 把坐标复制粘贴到pom.xml中
	3. 代码如下:
		//创建数据源对象
		BasicDataSource dataSource = new BasicDataSource();
		//设置数据库连接信息
		dataSource.setDriverClassName("com.mysql.jdbc.Driver");
		dataSource.setUrl("jdbc:mysql://localhost:3306/newdb3");
		dataSource.setUsername("root");
		dataSource.setPassword("123456");
		//设置初始连接数量
		dataSource.setInitialSize(3);
		//设置最大连接数量
		dataSource.setMaxActive(5);
		//从连接池中得到连接
		Connection conn = dataSource.getConnection();
		System.out.println(conn);

@Test 测试单元注解
只能对无参无返回值的方法进行单元测试

SQL的注入风险
select count(*) from t_user where username='libai' and password='admin1';
SQL注入的演示
	执行语句
		String sql = "insert into jdbcuser values(null,'"+name+"',"+age+")"; 
	输入:' or '1'='1	
	输出SQL拼接语句:
		select count(*) from t_user where username='asdfsdf' and password='' or '1'='1'
	出现登陆成功状态	
PreparedStatement对象
预编译的SQL对象
1. 为什么PreparedStatement可以避免SQL注入?
	因为预编译的SQL执行对象 在创建stat对象的时候已经将SQL进行编译并且把SQL语句的逻辑固定,不会因为后期替换进去的内容改变SQL语句		 	
	String sql = "select count(*) from t_user where username=? and password=?";	
	stat = conn.prepareStatement(sql);
	//替换问号的值
	stat.setString(1, username);
	stat.setString(2, password);	
	//执行SQL 
	rs = stat.executeQuery();		'不需要传入参数'	
2、好处
	1. 代码更直观避免了拼接SQL语句 
	2. 可以避免SQL注入 
	3. 执行效率略高于statement
	如果SQL语句中存在变量则使用PreparedStatement,如果没有变量则使用Statement
批量操作
将多次和数据库服务器的数据交互合并成一次,提高执行效率
	'添加到批量操作中'
	stat.addBatch(sql1);
	stat.addBatch(sql2);
	stat.addBatch(sql3);
	'执行批量操作'
	stat.executeBatch();
事务
1、设置自动提交的状态 
	conn.setAutoCommit(false/true);
2、提交 
	conn.commit();
3、回滚
	conn.rollback();
	
案例:实现超人有5000  蝙蝠侠100 让超人给蝙蝠侠转账2000,程序第一次运行转账成功 第二次转账成功第三次转账失败 
	create table person(id int primary key auto_increment,name varchar(10), money int);
	insert into person values(null,'超人',5000),(null,'蝙蝠侠',100);
获取自增主键的值
	Statement
		stat.executeUpdate(sql,Statement.RETURN_GENERATED_KEYS);
	PreparedStatement
		stat = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);	
	获取主键值		
		rs =stat.getGeneratedKeys();
		while(rs.next()){
			//得到返回的主键值
			int key=rs.getInt(1);
			System.out.println("自动生成的ID:"+key);
		}
获取元数据
元数据包括:数据库的元数据和表的元数据 
1. 数据库元数据里面保存一些和数据库相关的信息 如:数据库厂商名称,数据库驱动版本,数据库连接地址,用户名等等
	//得到数据库的元数据
	DatabaseMetaData dbmd = conn.getMetaData();
	System.out.println("驱动版本:"+dbmd.getDriverVersion());
	System.out.println("连接地址:"+dbmd.getURL());
	System.out.println("用户名:"+dbmd.getUserName());
	System.out.println("数据库厂商:"+dbmd.getDatabaseProductName());
2. 表的元数据里面保存一些和表相关的信息 如:表有多少字段,每个字段的名称、类型等 
	//从结果集中得到表的元数据
	ResultSetMetaData rsmd = rs.getMetaData();
	//得到表字段的数量
	int count = rsmd.getColumnCount();
	//得到每个字段的字段名和类型
	for (int i = 0; i < count; i++) {
		String name = rsmd.getColumnName(i+1);
		String type = rsmd.getColumnTypeName(i+1);
		System.out.println(name+":"+type);
	}
JDBC练习源代码
JAV中连接JDBC需要导包:
	import java.sql.***;	'必须导入java.sql.下面的包,否则会出错'
1、注册驱动
	Class.forName("com.mysql.jdbc.Driver");
2、获取连接对象
	Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/newdb3","root", "123456"); 
3、创建执行SQL语句对象
	Statement stat=conn.createStatement();	
4、执行SQL
	String sql = "create table if not exists jdbct1(id int primary key auto_increment,name varchar(10))";
	stat.execute(sql);
	//查询表中的数据,见到ResultSet就是用while循环
	String sql="select * from emp";
	rs=stat.executeQuery(sql);
	while(rs.next()){
		int id=rs.getInt("empno");
		String name=rs.getString("ename");
		int sal=rs.getInt("sal");
		System.out.println("ID:"+id+"   姓名:"+name+"   工资:"+sal);
	}
5、关闭资源	
		stat.close();
		conn.close();
6、解析jdbc.properties配置文件'文件路径src/main/resources'
	解析Properties后缀文件,获取对应的信息,properties后缀文件是以键值对方式存储信息
	例如:
		driver=com.mysql.jdbc.Driver
		url=jdbc:mysql://localhost:3306/newdb3
		username=root
		password=123456
		//创建属性对象
		Properties prop= new Properties();
		//得到文件输入流,Demo05当前类名
		InputStream ips=Demo05.class.getClassLoader().getResourceAsStream("jdbc.properties");
		//把流交给属性对象
		prop.load(ips);
		//获取数据,只能获取到字符串类型的数据
		String username = prop.getProperty("username");
		String password = prop.getProperty("password");
		System.out.println(username+": "+password);		
7、创建数据库连接池
		//创建数据源对象
		BasicDataSource dataSource= new BasicDataSource();
		//设置数据库连接信息
		dataSource.setDriverClassName("com.mysql.jdbc.Driver");
		dataSource.setUrl("jdbc:mysql://localhost:3306/newdb3");
		dataSource.setUsername("root");
		dataSource.setPassword("123456");
		//设置初始连接数量
		dataSource.setInitialSize(3);
		//设置最大连接数量
		dataSource.setMaxActive(5);
		//从连接池中得到连接
		Connection conn= dataSource.getConnection();		
		System.out.println(conn);	
8、解析配置文件与连接池配合使用
	private static BasicDataSource dataSource;
	static{
		//创建属性对象
		Properties prop= new Properties();
		//得到文件输入流
		InputStream ips=Demo05.class.getClassLoader().getResourceAsStream("jdbc.properties");
		//把流交给属性对象
		try {
			prop.load(ips);
			//获取数据,只能获取到字符串类型的数据
			String driver = prop.getProperty("driver");
			String url = prop.getProperty("url");
			String username = prop.getProperty("username");
			String password = prop.getProperty("password");
			/**创建数据库连接池*/
			//创建数据源对象
			dataSource= new BasicDataSource();
			//设置数据库连接信息
			dataSource.setDriverClassName(driver);
			dataSource.setUrl(url);
			dataSource.setUsername(username);
			dataSource.setPassword(password);
			//设置初始连接数量
			dataSource.setInitialSize(3);
			//设置最大连接数量
			dataSource.setMaxActive(5);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}		
	//从连接池中得到连接
	public static Connection getConn() throws SQLException{			
		return dataSource.getConnection();
	}
	//关闭打开的资源
	public static void close(Connection conn,Statement stat,ResultSet rs){
		try {
			if(rs!=null){
				rs.close();				
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		try {
			if(stat!=null){
				stat.close();				
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		try {
			if(conn!=null){
				//保证自动提交处于打开状态,必要时会在程序中关闭自动提交
				conn.setAutoCommit(true); 	
				conn.close();			
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}	
9、连接池做测试
	public class demo02 {			
		public static void main(String[] args) throws SQLException {
			threadTest t1=new threadTest();
			t1.start();
			threadTest t2=new threadTest();
			t2.start();
			threadTest t3=new threadTest();
			t3.start();
			threadTest t4=new threadTest();
			t4.start();
			threadTest t5=new threadTest();
			t5.start();
		}
	}
	class threadTest extends Thread{
		@Override
		public void run(){
			//获取连接
			try {
				Connection conn = DBUtils.getConn();
				System.out.println("获取连接!");
				//模拟耗时
				Thread.sleep(5000);
				//归还连接
				conn.close();
				System.out.println("归还连接!");
			} catch (SQLException e) {
				e.printStackTrace();
			}
			catch(Exception e){
				e.printStackTrace();
			}
		}
	}
10、PreparedStatement使用测试
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		System.out.println("请输入用户名:");
		String name = scan.nextLine();
		System.out.println("请输入年龄:");
		int age = Integer.parseInt(scan.nextLine());
		Connection conn = null;
		//预编译的SQL执行对象
		PreparedStatement stat = null;
		ResultSet rs = null;
		try {
			conn = DBUtils.getConn();
			String sql = "insert into jdbcuser values(null,?,?)";
			stat = conn.prepareStatement(sql);
			//把? 替换成真正的数据
			stat.setString(1, name);
			stat.setInt(2, age);
			//执行SQL语句
			stat.executeUpdate();

			System.out.println("插入数据成功!");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			DBUtils.closeSource(conn, stat, rs);
		}
	}	
11、批量插入练习
	public static void main(String[] args) {
		Connection conn = null;
		Statement stat = null;
		ResultSet rs = null;
		try {
			conn = DBUtils.getConn();
			stat = conn.createStatement();
			String sql1="insert into jdbcuser values(null,'张三',20)";
			String sql2="insert into jdbcuser values(null,'李四',21)";
			String sql3="insert into jdbcuser values(null,'王五',22)";				
			//stat.executeUpdate(sql1);
			//stat.executeUpdate(sql2);
			//stat.executeUpdate(sql3);
			//添加到批量操作中
			stat.addBatch(sql1);
			stat.addBatch(sql2);
			stat.addBatch(sql3);
			//执行批量操作
			stat.executeBatch();				
			System.out.println("插入数据成功!");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			DBUtils.closeSource(conn, stat, rs);
		}
	}	
	public static void main(String[] args) {
		Connection conn = null;
		PreparedStatement stat = null;
		ResultSet rs = null;
		try {
			long time0 = System.currentTimeMillis();
			conn = DBUtils.getConn();
			String sql = "insert into jdbcuser values(null,?,?)";
			stat = conn.prepareStatement(sql);
			for(int i=1;i<=100;i++){
				stat.setString(1,"name"+i);		//替换 ?
				stat.setInt(2, 100+i);		
				//添加到批量操作
				stat.addBatch();
				//每20条执行一次
				if(i%20==0){
					//执行批量操作
					stat.executeBatch();
					//清除批量操作
					stat.clearBatch();
				}
			}
			stat.executeBatch();			
			long time1 = System.currentTimeMillis();
			System.out.println("插入数据成功!耗时:"+(time1 - time0)+"ms");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			DBUtils.closeSource(conn, stat, rs);
		}
	}		
12、分页查询
	public static void main(String[] args) {
		Scanner scan=new Scanner(System.in);
		System.out.println("请输入查询页数:");
		int page= Integer.parseInt(scan.nextLine());
		if(page<=0){	//查询页数不可以为负数
			page=1;
		}
		System.out.println("请输入查询条数:");
		int num = Integer.parseInt(scan.nextLine());
		Connection conn = null;
		PreparedStatement stat = null;
		ResultSet rs = null;
		try {
			conn = DBUtils.getConn();
			String sql = "select * from jdbcuser limit ?,?";
			stat = conn.prepareStatement(sql);
			stat.setInt(1,(page-1)*num);
			stat.setInt(2, num);
			rs=stat.executeQuery();
			while(rs.next()){
				int id=rs.getInt("id");
				String name = rs.getString("name");
				System.out.println("ID:"+id+"  name:"+name);
			}
			System.out.println("插入数据成功!");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			DBUtils.closeSource(conn, stat, rs);
		}
	}	
13、转账练习
	public static void main(String[] args) {
		Connection conn = null;
		Statement stat = null;
		ResultSet rs = null;
		try {
			conn = DBUtils.getConn();
			conn.setAutoCommit(false);
			stat =conn.createStatement();
			String sql1 = "update person set money=money-2000 where id=1";
			String sql2 = "update person set money=money+2000 where id=2";			
			stat.executeUpdate(sql1);
			stat.executeUpdate(sql2);
			//得到超人剩余的钱数,如果大于等于0,则允许转账,否则回滚
			rs=stat.executeQuery("select money from person where id=1");
			while(rs.next()){
				int money = rs.getInt("money");
				if(money>=0){
					System.out.println("转账成功!");
					conn.commit();	//提交
				}
				else{
					System.out.println("转账失败!");
					conn.rollback();	//回滚
				}
			}
			System.out.println("操作成功!");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			DBUtils.closeSource(conn, stat, rs);
		}
	}	
13、向表中插入数据,队名并且获取主键,根据主键插入队员,实现关系表
	public static void main(String[] args) {
		//createTable();
		Scanner scan=new Scanner(System.in);
		System.out.println("请输入球队名称:");
		String teamName = scan.nextLine();
		System.out.println("请输入球员名称:");
		String playName = scan.nextLine();
		scan.close();
		Connection conn = null; 
		PreparedStatement stat = null;
		ResultSet rs = null;
		try {
			conn = DBUtils.getConn();
			/**
			* 查询是否存在用户输入的球队
			*/
			String sql = "select * from team where name=?";
			stat = conn.prepareStatement(sql);
			stat.setString(1, teamName);
			rs = stat.executeQuery();
			int tid =-1;
			while(rs.next()){
				//得到已经保存的球队id
				tid = rs.getInt("id");
			}
			//判断是否保存过球队
			if(tid==-1){
				sql = "insert into team values(null,?)";
				stat.close();
				//获取主键值
				stat = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);	
				stat.setString(1, teamName);
				stat.executeUpdate();
				rs.close();
				//得到主键值
				rs = stat.getGeneratedKeys();
				while(rs.next()){
					tid = rs.getInt(1);
					System.out.println("teamId="+tid);
				}			
			}
			//插入球员
			sql = "insert into player values(null,?,?)";
			stat.close();
			stat = conn.prepareStatement(sql);
			stat.setString(1, playName);
			stat.setInt(2, tid);
			//执行
			stat.executeUpdate();
			System.out.println("操作成功!");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			DBUtils.closeSource(conn, stat, rs);
		}
	}	
14、获取元数据
	public static void main(String[] args) {
		Connection conn = null;
		Statement stat = null;
		ResultSet rs = null;
		try {
			conn = DBUtils.getConn();
			//得到数据库的元数据
			DatabaseMetaData dbmd=conn.getMetaData();
			System.out.println("驱动版本:"+dbmd.getDriverMajorVersion());
			System.out.println("链接地址:"+dbmd.getURL());
			System.out.println("用户名:"+dbmd.getUserName());
			System.out.println("数据库厂商:"+dbmd.getDatabaseProductName());		
			stat=conn.createStatement();
			rs = stat.executeQuery("select * from emp");
			//从结果集体中得到表的元数据
			ResultSetMetaData rsmd=rs.getMetaData();
			int count = rsmd.getColumnCount();
			//得到表字段的数量
			System.out.println("表字段数量:"+count);
			//得到每个字段的字段名和类型
			for(int i=0;i<count;i++){
				String name = rsmd.getColumnName(i+1).toLowerCase();
				String type= rsmd.getColumnTypeName(i+1).toLowerCase();
				System.out.println(name+"  "+type);
			}
				
			System.out.println("操作成功!");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			DBUtils.closeSource(conn, stat, rs);
		}
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值