MySql & JDBC
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySql & JDBC相关的知识,希望对你有一定的参考价值。
1、什么是数据库?
数据库就是存储数据的仓库,其本质是一个文件系统,数据按照特定的格式将数据存储起来,用户可以通过SQL对数据库中的数据进行增加、修改、删除、及查询操作。
数据库系统类型(历史发展):
网状型数据库
层次型数据库
关系数据库 ---理论最成熟、应用最广泛
面向对象数据库
常见的数据库(软件):
Oracle
DB2
SQLServer
SyBase
SQLite
Java相关: MYSQL Oracle
2、数据库和表
数据表示存储数据的逻辑单元,可以把数据表想象成有行和列组成的表格,其中每一行也被称为一条记录,每一列也被称为一个字段。(建表时:需要指定该表包含多少列,每列的数据的类型信息,无须指定包含多少行,数据库的行是动态改变的。特殊列被称为主键列。)
3、SQL语句
什么是SQL语句?
Structured Query Language 结构化查询语言。关系数据库语言的国际标准。
SQL分类?
DDL:Data Definition Language 数控定义语言; 操作数据库对象的语句,包括创建create、删除drop、修改alter等(结构)
DML:Data Manipulation Language 数据操作语言,用来对数据库表的记录进行更新,包括插入insert 、 删除 delete 、 更新 update等 (数据)
DQL: Data Query Language 数据查询语言,用来查询数据库中表的记录。关键字:select,from where等
DCL:Data Control Language 数据控制语言;用来定义数据库的访问权限和安全级别,及创建用户:关键字 grant等
show databases; 查看当前实例下包含多少个数据库
create database if not exists 数据库名; 创建新的数据库
create database 数据库名 character set 字符集;
例子:create database web2 character set gbk;
查看某个数据库的定义的信息:show create database 数据库名;
drop database 数据库名; 删除指定数据库
use 数据库名; 切换数据库、
查看正在使用的数据库: select database();
show tables; 查询数据库下包含多少数据表
desc 表名; 查看该表有多少列,每列的数据类型信息
DDL语句:
创建表:
create table 表名
(
定义多个列定义;
);
修改表结构:
添加列:
alter table 表名
add ( 可以有多个列定义; 字段名 类型 [约束] , );
约束:
NOT NULL : 非空
UNIQUE:唯一约束
PRIMARY KEY : 主键
(test_id int auto_increment primary key); 自增长特性,不能指定该列值
FOREIGN KEY: 外键
CHECK:检查
修改列的类型、长度、约束:
alter table 表名 modify 要修改的字段名 类型(长度) 约束;
修改列的列名:
alter table 表名
change 旧列名 新列名 类型(长度) [约束];
删除表的列:
alter table 表名 drop 表列名;
修改表名:
atler table 表名
rename to 新表名;
修改表字符集:
alter table 表名
character set 编码;
删除表:
drop table 表名;
DML语法:
插入新数据 insert into
修改已有数据 update
删除不需要的数据 deleter from
insert:
语法:
insert into 表名 (列名1,列名2.....)values (值1,值2,....)......向表中插入某些列
insert into 表 values (值1,值2, 值3 ....)......向表中插入所有列
注意:
1.列名数与values后面的值得个数相等
2.列的顺序与插入的值得顺序一致
3.列名的类型与插入的值要一致
4.插入值得时候不能超过最大长度
5.值如果是字符串或者日期需要加引号‘’(一般都是单引号)
插入数据中文乱码问题解决办法:
方式一:[不建议]
直接修改数据库安装目录里面的 my.ini 文件的
第57行
default-character-set = utf8
方式二:
set names gbk;
update:
不带条件的:
update 表名 set 字段值= 值
它会将该列的所有记录都更改。
带条件的:
update 表名 set 字段值 = 值 where 条件
delete:
带条件的:
delete from 表名 where 条件;
不带条件:
delete from 表名; //记录全部删除
面试题:
说说delete 与truncate的区别?
Delete删除的时候是一条一条的删除记录,它配合事务,可以将删除的数据找回。
Truncate删除,它是将整个表摧毁,然后再创建一张一模一样的表。它删除的数据无法找回。
truncate table 表名;
start transaction; 开启事务
delete from 表名;
select * from 表名; //无数据
rollback; //回滚下
select * from 表名; //数据返回了
start transaction; 开启事务
truncate table 表名;
select * from 表名; //无数据
rollback; //回滚下
select * from 表名 ; 还是无数据
insert into 表名 values (值1,值2,....)
注:transaction再添加数据uid重置,从1开始,而delete删除uid不会重置。(udi自增长的主键id,即定义如下:id int auto_increment primay key)。
4、DQL SQL查询 注:最最重要,用到最多
语法:
select 列名,列名 from 数据源 where 条件;
#创建商品表
create table product(
pid int primary key auto_increment,
pname varchar(20),
price double,
pdate timestamp
)
#自动增长列:auto_increment,要求:1,必须整型(int) 2.必须是主键
insert into product values (null,‘谭妮平‘,0.01,null);
insert into product values (null,‘李士雪‘,38,null);
insert into product values (null,‘左慈‘,-998,null);
insert into product values (null,‘黄迎‘,99999,null);
insert into product values (null,‘南国强‘,99998,null);
insert into product values (null,‘士兵‘,1,null);
insert into product values (null,‘李士兵‘,698,null);
1.3.3 简单查询
1.查询所有商品
select * from product;
2.查询商品名和商品价格
select pname, price from product;
3.查询所有商品信息使用表别名
select * from product as p;
4.查询商品名,使用列别名
select pname as p from product;
5.去掉重复值(按照价格,需有数据)
select distinct(price) from product;
6.将所有的商品的价格+10进行显示
select pname, price+10 from product;
1.3.4 条件查询
比较运算符
> 、 < = >= <= <> (不等于)
between ... .and ... 显示在某一区间的值(含头含尾)
in () 显示在in列表中的值
like 模糊查询,like语句中,%代表0个或多个任意字符,_代表一个字符
转义字符:MySQL使用反斜线(\)作为转义字符:
select * from student where sname like ‘\_%‘ (选出所有名字以下划线开头的学生)
is null 判断是否为空
逻辑运算符:
and 多个条件同时成立
or 多个条件任一成立
not 不成立 , 例: where not (salary > 100)
1.查询商品名称为"左慈"的商品信息
select * from product where pname = ‘左慈‘
2.查询价格>60元的所有商品信息
select * from product where price > 60
3.查询商品名称含有"士"字的商品信息
select * from product where pname like ‘%士%‘
4.查询商品id在(3,6,9)范围内的所有商品信息
select * from product where pid in (3,6,9);
1.3.5 排序(asc/desc)
1.查询所有的商品,按价格进行排序(升序、降序)
select * from product order by price asc; //升序
select * from product order by price desc; //降序
2.查询名称有"士"的商品信息并且按照价格降序排序
select * from product where pname like ‘%士%‘ order by price desc;
1.3.6 聚合
常用聚合函数: sum()求和, avg()平均, max()最大值,min()最小值,count()计数
注意:聚合函数不统计null值
1.获得所有商品的价格的总和
select sum(price) from product;
2.获得所有商品的平均价格
select avg(price) from product;
3.获得所有商品的个数
select count(*) from product;
select count(distinct pname) from product;
1.3.7 分组
1.添加分类id (alter table product add cid varchar(32);)
2.初始化数据
update product set cid=‘1‘;
update product set cid=‘2‘ where pid in (5,6,7);
查询:
1.根据cid字段分组,分组后统计商品的个数。
select cid , count(*) from product group by cid;
2.根据cid分组,分组统计每组商品的平均价格,并且平均价格大于20000元。
select cid , avg(price) from product group by cid having avg(price) >20000;
注意:如果需要对分组进行过滤,则应该使用having子句,having子句后面也是一个条件表达式,只有满足该条件表达式的分组才会被选出来。
查询总结:
select * | 字段 (一般放在"的"后面的内容都是要查询的字段)
from 表
where 查询条件
group by 分组字段
having 分组条件 分组后带有条件只能使用having
order by 排序字段 asc 、desc (必须放在最后)
5、回顾JDBC
设置工作空间的编码:
windows->workspace->Text file encoding -> other UTF-8。
创建JavaProject。
JDBC概述:
Java DataBase Connectivity: java 数据库了解。
1、JDBC是一种用于执行SQL语句的Java API;
2、JDBC可以为多种关系数据库提供统一访问入口;
3、JDBC由一组Java工具类和接口组成。
应用程序 <----> JDBC <----> MySQL驱动 <-----> MySQL
a、手动添加jar包到工程中,Bulid Path---> Add ---> 出现小奶瓶就添加成功!
Junit测试:
package com.scalpel.test;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class TestUnit {
public static void main(String[] args) {
System.out.println("aa");
}
@Test
public void testJunit()
{
System.out.println("hello junit!");
}
@Before
public void testBefore()
{
System.out.println("before!");
}
@After
public void testAfter()
{
System.out.println("after");
}
}
注:运行只能点击testJunit() Run As Junit Test.....
before!
hello junit!
after
JDBC开发步骤:
1、注册驱动
Class.forName("com.mysql.jdbc.Driver");
2、获得连接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/web","root","12345678");
DriverManager.getConnection(url, username, password):三个参数分别是url:jdbc的地址(位置,网址) , username 用户名, password 密码。
3、获得语句执行者
通过Connection对象创建Statement对象。
Statement stmt = conn.createStatement();
4、执行sql语句
stmt.executeUpdate(String sql语句) 执行DML和DDL语句。 insert update delete
(注:返回受影响的行数!!!)
stmt.executeQuery(String sql语句) 执行DQL 语句 select 语句 。
(注:返回代表查询结果的ResultSet对象!!!)
ResultSet 实质是一个查询结果集,记录指针的初始位置是第一行之前。
(其他方法:privious()/first()/last()/beforeFist()等等)
ResultSet rs = stmt.executeQuery(sql语句)
5、处理结果
rs.next();
rs.getXxx();
6、释放资源
栈(先进后出):
rs.close();
stmt.close();
con.close();
注:为什么要释放资源?
JUnit Test:
package com.scalpel.test;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class TestUnit {
public static void main(String[] args) {
System.out.println("aa");
}
@Test
public void testJunit()
{
System.out.println("hello junit!");
}
@Before
public void testBefore()
{
System.out.println("before!");
}
@After
public void testAfter()
{
System.out.println("after");
}
}
JDBC连接以及PreparedStatement执行SQL语句,防止SQL注入攻击问题
package com.scalpel.test;
import java.sql.*;
import org.junit.Test;
public class TestLogin {
@Test
public void testLogin()
{
try {
login1("ct", "123"); //注:如果login (“‘or true or’”,"");也是登录成功
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void login( String username, String password ) throws ClassNotFoundException, SQLException
{
/**
* 用户登录方法
* @author ctmc
*
*/
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接
Connection conn =DriverManager.getConnection("jdbc:mysql://localhost:3306/web","root", "12345678");
//3.创建执行sql语句的对象
Statement stmt = conn.createStatement();
//4.书写一个sql语句
String sql = "select * from user where name = ‘" + username + "‘ and password = ‘" + password + "‘" ;
//5.执行sql语句
ResultSet rs = stmt.executeQuery(sql);
//6.对结果集进行处理
if ( rs.next())
{
System.out.println("恭喜你,"+username+",登录成功!");
System.out.println(sql);
}else
{
System.out.println("账号或密码错误");
}
//7.关闭资源
if(rs != null)
{
rs.close();
}
if( stmt != null )
{
stmt.close();
}
if(conn != null )
{
conn.close();
}
}
public void login1 ( String username, String password ) throws ClassNotFoundException, SQLException
{
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接
Connection conn =DriverManager.getConnection("jdbc:mysql://localhost:3306/web","root", "12345678");
//3.编写sql语句
String sql = "select * from user where name = ? and password = ?";
//4.创建预处理对象
PreparedStatement pst = conn.prepareStatement(sql);
//5.设置参数(给占位符)
pst.setString(1, username);
pst.setString(2, password);
//6.执行查询操作
ResultSet rs = pst.executeQuery();
//7.对结果集进行处理
if ( rs.next())
{
System.out.println("恭喜你,"+username+",登录成功!");
System.out.println(sql);
}else
{
System.out.println("账号或密码错误");
}
//8.关闭资源
if(rs != null)
{
rs.close();
}
if( pst != null )
{
pst.close();
}
if(conn != null )
{
conn.close();
}
}
}
注:使用PreparedStatement 防止SQL注入攻击!!!?代表什么
6、Limit关键字进行查询操作(分页查询)
a、说出limit关键字两个参数的含义
(limit 2, 2) : 第一个2起始位置, 第二个2每页显示的数目
每页显示3条件记录,要查询第3页。
第一参数等于查询的页数减一乘以每页显示的数目,第二个参数是每页显示的数目
select * from product limit 6,3;
b、写出limit关键字查询数据SQL语句
总结:
1、说出JDBC的概念
2、说出JDBC的开发步骤
3、能够使用DriverManager类 (作用,加载驱动方法,获取连接方法)
4、能够使用Connection接口 (作用,获取接口的方法)
5、能够使用Statement接口
6、能够使用ResultSet接口
7、MySQL多表创建、查询
外键:
从表外键的值是对主表主键的引用。
从表外键类型,必须与主表主键类型一致。
声明外键约束:
alter table 从表 add [constraint] [外键名称] foreign key (从表外键字段名) references 主表 (主表的主键);
用于删除外键约束的,一般建议“_fk”结尾
alter table 从表 drop foreign key 外键名称
使用外键的目的:
保证数据完整性。
注意事项:
从表不能添加一条主表中不存在的记录。
主表不能删除,从表中已经引用的记录。
表与表之间的关系
a、一对多关系
一对多建表原则:在多的一方创建一个字段,字段作为外键指向少的一方的主键。
alter table 从表(product) add foreign key (外键cno) references 主表(category)主键(cid)
b、多对多关系
多对多关系建表原则:需要创建第三张表,中间表中至少两个字段,这两个字段分别作为外键指向各自一方的主键。
alter table 从表(stu_course ) add foreign key(sno) references stu(sid);
alter table 从表(stu_course ) add foreign key(con) references course(cid);
c、一对一
两种建表原则:
外键唯一:主表的主键和从表的外键唯一,形成主外键关系,外键唯一unique。
外键是主键:主表的主键和从表的主键,形成主外键关系。
多表查询:
a、交叉连接查询(基本不用)
select * from A,B;
b、内连接查询(使用关键字inner join --inner可以省略)
隐式内连接:select * from A,B where 条件
显示内连接: select * from A inner join B on 条件 ;
c、外连接查询(使用的关键字 outer join --outer 可以省略)
左外连接:left outer join
select * from A left outer join B on 条件;
右外连接:right outer join
select * from A right outer join B on 条件;
左外连接与右外连接的区别:
左外连接:左表全部及两个表的交集
右外连接:查询的是右边表的全部及两个表的交集。
内连接:查询两个表的交集。
全外连接:
d、子查询
子查询:一条select语句结果作为另一条select语法一部分(查询条件,查询结果,表等)
8、JDBC工具类抽取方式
使用JDBC发送select语句完成单表【查询】操作。
//类:JDBCUtils_V1
package com.scalpel.jdbc;
/**
* 提供获取连接和释放资源的方法。
* @author ctmc
*
*/
import java.sql.*;
public class JDBCUtils_V1 {
//连接Connection方法
public static Connection getConnection()
{
Connection conn = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/web","root", "12345678");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
//释放所有资源方法
public static void release(Connection conn, PreparedStatement psmt, ResultSet rs)
{
if( rs!= null )
{
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if( psmt != null )
{
try {
psmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if( conn != null )
{
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
//测试类TestUtils
package com.scalpel.test;
import java.sql.*;
import org.junit.Test;
import com.scalpel.jdbc.JDBCUtils_V1;
/**
* 测试工具类
* @author ctmc
*
*/
public class TestUtils {
/**
* 根据id查询用户信息.
*/
@Test
public void testFindUserById()
{
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
//1.获取连接
conn = JDBCUtils_V1.getConnection();
String sql = "select * from user where id = ? ";
//3.获取执行SQL语句对象
pstmt = conn.prepareStatement(sql);
//4.设置参数
pstmt.setInt(1, 2);
//5.执行查询操作
rs = pstmt.executeQuery();
//6.处理结果集
while ( rs.next() )
{
System.out.println(rs.getString("name")+"-----"+rs.getString("password"));
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//7.释放资源
JDBCUtils_V1.release(conn, pstmt, rs);
}
}
}
注意:1、PreparedStatement的用法。2、释放资源为什么要放在finally中,能不能放在try中?
PreparedStatement的用法:
在数据库的操作过程中,PreparedStatement 对象是一个很不起眼但是记为重要的接口对象,它继承 于Statement,并与之在两方面有所不同:
1)PreparedStatement 实例包含已编译的 SQL 语句。这就是使语句“准备好”。包含于 PreparedStatement 对象中的 SQL 语句可具有一个或多个 IN 参数。IN参数的值在 SQL 语句创建时未被指定。相反的,该语句为每个 IN 参数保留一个问号(“?”)作为占位符。每个问号的值必须在该语句执行之前,通过适当的setXXX 方法来提供。
2)由于 PreparedStatement 对象已预编译过,所以其执行速度要快于 Statement 对象。因此,多次执行的 SQL 语句经常创建为 PreparedStatement 对象,以提高效率。
例如:SQL语句为:String sql = select * from user where id = ?(整型) and name = ?(字符串);
在pstmt.setXXX设置是,第一个参数要整型,第二个参数为字符串类型。
在ResultSet 获得结果。
rs.getString(1) 或者 rs.getString("name");得到的结果一样 (数据库该表第一位为name)!
9、使用properties配置文件
开发中获得连接的4个参数(驱动、URL、用户名、密码)通常都保存在配置文件中,方便后期维护,程序如果需要更换数据库,只需要修改配置文件即可。
通常情况下,我们习惯使用properties文件,此文件我们将做如下要求:
a、文件位置:任意,建议放在src下(非web程序)
b、文件名称:任意,扩展名为properties
c、文件内容:一行一组数据,格式是:“key=value”(不要有空格)
!key命名自定义,如果是多个单词,习惯使用点分隔,例如:jdbc.driver
@value值不支持中文,如果需要使用非英文字符,将进行unicode转换
创建properties配置文件(注:不要有空格)
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/web
username=root
password=12345678
加载配置文件----ResourceBundle对象
package com.scalpel.jdbc;
/**
* 提供获取连接和释放资源的方法。
* @author ctmc
*
*/
import java.sql.*;
import java.util.ResourceBundle;
public class JDBCUtils_V2 {
private static String driver;
private static String url;
private static String username;
private static String password;
/**
* 静态代码块加载配置文件信息。
* */
static
{
ResourceBundle rb = ResourceBundle.getBundle("db");
driver = rb.getString("driver");
url = rb.getString("url");
username = rb.getString("username");
password = rb.getString("password");
}
//连接Connection方法
public static Connection getConnection()
{
Connection conn = null;
try {
Class.forName(driver);
conn = DriverManager.getConnection(url,username,password);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
//释放所有资源方法
public static void release(Connection conn, PreparedStatement psmt, ResultSet rs)
{
if( rs!= null )
{
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if( psmt != null )
{
try {
psmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if( conn != null )
{
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
添加表信息:
/**
* 添加用户信息方法
*/
@Test
public void testAdd()
{
Connection conn = null;
PreparedStatement pstmt = null;
try {
//1.获取连接
conn = JDBCUtils_V2.getConnection();
//2.编写SQL语句
String sql = "insert into user values(?,?,null)";
//3.获取执行sql语句对象
pstmt = conn.prepareStatement(sql);
//4.设置参数
pstmt.setString(1,"zll");
pstmt.setString(2,"zll");
//5.执行插入操作,返回一个值是否添加成功。
int row = pstmt.executeUpdate();
if ( row > 0 )
{
System.out.println("添加信息成功!");
}
else
{
System.out.println("添加失败!");
}
} catch (Exception e) {
throw new RuntimeException(e);
}finally {
//6.释放资源
JDBCUtils_V2.release(conn, pstmt, null);
//注:无参数设置为null
}
}
根据ID删除用户信息:
配置文件加载方法改变:
package com.scalpel.jdbc;
/**
* 提供获取连接和释放资源的方法。
* @author ctmc
*
*/
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
import java.util.ResourceBundle;
public class JDBCUtils_V3 {
private static String driver;
private static String url;
private static String username;
private static String password;
/**
* 静态代码块加载配置文件信息。
* */
static
{
try {
//1.通过当前类获取类加载器
ClassLoader cl = JDBCUtils_V3.class.getClassLoader();
//2.通过类加载器的方法获得一个输入流、
InputStream is = cl.getResourceAsStream("db.properties");
//3.创建一个properties对象
Properties props = new Properties();
//4.加载输入流
props.load(is);
//5.获取相关参数的值
driver = props.getProperty("driver");
url = props.getProperty("url");
username = props.getProperty("username");
password = props.getProperty("password");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
is.close();
}
}
//连接Connection方法
public static Connection getConnection()
{
Connection conn = null;
try {
Class.forName(driver);
conn = DriverManager.getConnection(url,username,password);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
//释放所有资源方法
public static void release(Connection conn, PreparedStatement psmt, ResultSet rs)
{
if( rs!= null )
{
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if( psmt != null )
{
try {
psmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if( conn != null )
{
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
注:实现所有资源释放的方法,上例中使用多个try-catch块,将资源释放,容易理解。但是多个try-catch并列,catch块中不能抛出异常,否则将阻止程序的继续执行。
应该修改为:try-catch-finally嵌套,资源释放时如果出错,将通知调用者,还可以继续释放其他资源。
/**
* 根据id删除信息的方法
*/
@Test
public void testDleteById()
{
Connection conn = null;
PreparedStatement pstmt = null;
try {
//1.获取连接
conn = JDBCUtils_V3.getConnection();
//2.编写SQL语句
String sql = "delete from user where id = ?";
//3.获取执行sql语句对象
pstmt = conn.prepareStatement(sql);
//4.设置参数
pstmt.setInt(1,3);
//5.执行插入操作
int row = pstmt.executeUpdate();
if ( row > 0 )
{
System.out.println("删除信息成功!");
}
else
{
System.out.println("删除失败!");
}
} catch (Exception e) {
throw new RuntimeException(e);
}finally {
//6.释放资源
JDBCUtils_V2.release(conn, pstmt, null);
}
}
10、Java项目读取properties文件的几种方法
一、项目中经常会需要读取配置文件(properties文件),因此读取方法总结如下:
1、通过java.util.Properties读取
Java代码
- Properties p=new Properties();
- //p需要InputStream对象进行读取文件,而获取InputStream有多种方法:
- //1、通过绝对路径:InputStream is=new FileInputStream(filePath);
- //2、通过Class.getResourceAsStream(path);
- //3、通过ClassLoader.getResourceAsStream(path); 通过自己的类加载最稳当!?why?
- p.load(InputStream is);
- is.close();
- p.getString(String(key))
2、通过java.util.ResourceBundle读取
Java代码
- ResourceBundle rb=ResourceBundle.getBundle(packageName);
- rb.getString(String key);
11、JDBC 连接池&DBUtils
连接池:解决资源浪费,提供代码性能。
本小节目标:
使用DBCP,C3P0连接池完成基本数据库的操作。
使用DBUtils完成CRUD的操作。
数据库连接池的解决方案是:
当应用程序启动时,系统主动建立足够的数据库连接,并将这些连接组成一个连接池。每次应用程序请求数据库连接时,无须重新打开连接,而是从连接池中取出已有的连接使用,使用完后不再关闭数据库连接,而是直接将连接归还给连接池。通过使用连接池,将大大提高程序的运行效率。
数据库连接池是Connection 对象的工程。数据库连接池的常用参数如下。
a、数据库的初始连接数
b、连接池的最大连接数
c、连接池的最小连接数
d、连接池每次增加的容量
公共接口:javax.sql.DataSource。
常见的连接池:DBCP 、 C3P0 (主要)
一、自定义连接池
1、创建连接池实现(数据源),并实现接口javax.sql.DataSource。因为我们只使用该接口中getConnection()方法。
2、提供一个集合,用于存放连接,因为移除、添加操作过多,所以选择LinkedList
代码例子:
提供获取连接和释放资源的方法还是使用JDBCUtils_V3.java
package com.scalpel.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.logging.Logger;
import javax.sql.DataSource;
import javax.sql.PooledConnection;
import com.scalpel.jdbc.JDBCUtils_V3;
public class MyDataSource implements DataSource {
//1.创建一个容器,用于存储Connection对象
private static LinkedList<Connection> pool = new LinkedList<Connection>();
//2.创建5个连接放到容器中去
static
{
for (int i = 0; i < 5; i++)
{
Connection conn = JDBCUtils_V3.getConnection();
pool.add(conn);
}
}
/**
* 重写获取一个连接的方法
*/
@Override
public Connection getConnection() throws SQLException {
Connection conn = null;
//3.使用前先判断
if( pool.size() == 0 )
{
//4.池子里面没有,我们在创建一些
for (int i = 0; i < 5; i++)
{
conn = JDBCUtils_V3.getConnection();
pool.add(conn);
}
}
//5.从池子里面获取一个连接对象Connection,list的remove()方法
//删除并返回index索引处的元素
conn = pool.remove(0);
return conn;
}
/**
* 归还连接对象到连接池中去
*/
public void backToPool ( Connection conn )
{
//连接用完后,再归还到连接池中,直接插入到list集合中。
pool.add(conn);
}
@Override
public PrintWriter getLogWriter() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public int getLoginTimeout() throws SQLException {
// TODO Auto-generated method stub
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public boolean isWrapperFor(Class<?> arg0) throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public <T> T unwrap(Class<T> arg0) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
// TODO Auto-generated method stub
return null;
}
}
测试方法:
package com.scalpel.jdbc.test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import org.junit.Test;
import com.scalpel.DataSource.MyDataSource;
public class TestMyDataSource {
@Test
public void testAddUser()
{
Connection conn = null;
PreparedStatement pstmt = null;
//创建自定义连接池对象
MyDataSource dataSource = new MyDataSource();
try
{
//2.从池子中获取连接
conn = dataSource.getConnection();
String sql = "insert into user values(?,?,null)";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "xixi");
pstmt.setString(2, "456");
int rows = pstmt.executeUpdate();
if ( rows > 0 )
{
System.out.println("添加成功!");
}
else
{
System.out.println("添加失败!");
}
} catch (Exception e) {
throw new RuntimeException();
}finally {
dataSource.backToPool(conn);
}
}
}
注:如果插入数据为中文,会出现数据库中乱码显示?
怎样解决这个问题?
自定义连接池代码实现改进(增强close方法):
自定义连接池中存在的严重问题,用户调用getConnection()获得连接后,必须使用release()方法进行连接的归还,如果用户调用conn.close()将连接真正的释放,连接池中将出现无连接可以。
方法增强的办法:
a、继承,子类继承父类,将父类的方法进行复写,从而进行增强。
使用前提:必须有父类,且存在继承关系。
b、装饰者设计模式,此设计模式专门用于增强方法。
使用前提:必须有接口
缺点:需要将接口的所有方法都实现
c、动态代理:在运行时动态的创建代理类,完成增强操作。与装饰者相似
使用前提:必须有接口
难点:需要反射技术
d、字节码增强,运行时创建目标类子类,从而进行增强
常见第三方框架:cglib 、javassist等。
C3P0连接池:
C3P0开源免费的连接池!目前使用它的开源项目有:Spring 、 Hibernate等。使用第三方工具需要导入jar包,C3P0使用时还需要添加配置文件c3p0-config.xml(固定)
在增加、删除、修改等操作中有很多相同的代码,只有少部分的不同。对于那些不同的地方,我们使用传参的方法来解决!!!
如果只使用JDBC进行开发,我们会发现冗余代码过多,为了简化JDBC开发,本案例我们讲采用apache commons组件一个成员:DBUtils。
DBUtils就是JDBC的简化开发工具包。需要使用技术:连接池(获得连接),SQL语句都没有少。
JavaBean组件:
JavaBean就是一个类,在开发中常用语封装数据。具有如下特性:
a、需要实现接口:java.io.Serializable (通常省略)
b、提供私有字段:private 类型,字段名;
c、提供getter、setter方法;(空白处,source->setter getter)
d、提供无参构造
放在com.scalpel.domain包中(构造方法)
package com.scalpel.domain;
public class User {
private int id;
private String password;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User()
{
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
注:JavaBean的私有字段名,必须与数据库中的列名一样!!!
否则查询出来就是null。必须一样。
DBUtils概述:
DBUtils是java编程中的数据库操作实用工具,小巧简单实用。
DBUtils封装了对JDBC的操作,简化了JDBC操作,可以少些代码。
DBUtils三个核心功能介绍:
a、QueryRunner中提供对sql语句操作的API
核心类:
QueryRunner( DataSource ds),连接池
update(String sql, Object ....params),执行更新数据
query(String sql, ResultSetHandler<t> rsh, Object ....params),执行查询
b、ResultSetHandler接口,用于定义select操作后,怎样封装结果集
BeanHandler: 将结果集中第一条记录封装到一个指定的javaBean中。
BeanListHandler:将结果集中每一条记录封装到指定的javaBean中,将这些javaBean再封装到集合中。
ScalarHandler
c、DbUtils类,它就是一个工具类,定义了关闭资源与事务处理的方法
c3p0-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///web</property>
<property name="user">root</property>
<property name="password">12345678</property>
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">20</property>
</default-config>
<named-config name="scalpel">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///web</property>
<property name="user">root</property>
<property name="password">12345678</property>
</named-config>
</c3p0-config>
C3P0Utils.java
package com.scalpel.jdbc.utils;
import java.sql.Connection;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3P0Utils {
private static ComboPooledDataSource dataSource =
new ComboPooledDataSource("scalpel");
public static DataSource getDataSource()
{
return dataSource;
}
public static Connection getConnection()
{
try {
return dataSource.getConnection();
} catch (Exception e) {
throw new RuntimeException();
}
}
}
TestDBUtils.java
package com.scalpel.jdbc.test;
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import org.junit.Test;
import com.scalpel.jdbc.utils.C3P0Utils;
/**
* 测试DBUtils工具类
* @author ctmc
*
*/
public class TestDBUtils {
@Test
public void testDeleteUserById()
{
try {
//1.创建核心类QueryRunner
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
//2.编写sql语句
String sql = "delete from user where id = ?";
//3.为占位符设置值
Object[] params = {7};
//4.执行添加操作
int rows = qr.update(sql,params);
if ( rows > 0 )
{
System.out.println("删除成功");
}
else
{
System.out.println("删除失败");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 添加用户
*/
@Test
public void testAddUser()
{
try {
//1.创建核心类QueryRunner
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
//2.编写sql语句
String sql = "insert into user values(?,?,null)";
//3.为占位符设置值
Object[] params = {"xizll","789"};
//4.执行添加操作
int rows = qr.update(sql,params);
if ( rows > 0 )
{
System.out.println("添加成功");
}
else
{
System.out.println("添加失败");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
查询select代码:
package com.scalpel.jdbc.test;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.junit.Test;
import com.scalpel.domain.User;
import com.scalpel.jdbc.utils.C3P0Utils;
public class TestDBUtilsSelect {
/*
* 查询所有用户个数
*/
@Test
public void testUserNum()
{
try {
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
String sql = "select count(*) from user";
long num = (long) qr.query(sql, new ScalarHandler());
System.out.println(num);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*
* 根据id查询用户
*/
@Test
public void testQueryUserById()
{
try {
//1.获取核心类queryRunner
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
//2.编写sql语句
String sql = "select * from user where id = ?";
//3.为占位符设置值
Object[] params = {9};
//4.执行查询操作
User user = qr.query(sql, new BeanHandler<User>(User.class), params);
//5.对结果集单个进行输出
System.out.println(user.getName()+" : " + user.getPassword());
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 查询所有用户
* */
@Test
public void testQueryAll()
{
try {
//1.获取核心类queryRunner
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
//2.编写sql语句
String sql = "select * from user";
//3.执行查询操作
List<User> users = qr.query(sql, new BeanListHandler<User>(User.class));
//4.对结果集集合进行遍历
for (User user : users)
{
System.out.println(user.getName()+" : " + user.getPassword());
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
以上是关于MySql & JDBC的主要内容,如果未能解决你的问题,请参考以下文章