一、什么是数据库?
数据库就是存储数据的仓库,其本质是一个文件系统,数据按照特定的格式将数据存储起来,用户能够经过SQL对数据库中的数据进行增长、修改、删除、及查询操做。
数据库系统类型(历史发展):
网状型数据库
层次型数据库
关系数据库 ---理论最成熟、应用最普遍
面向对象数据库
常见的数据库(软件):
MYSQL
Oracle
DB2
SQLServer
SyBase
SQLite
Java相关: MYSQL Oracle
二、数据库和表
数据表示存储数据的逻辑单元,能够把数据表想象成有行和列组成的表格,其中每一行也被称为一条记录,每一列也被称为一个字段。(建表时:须要指定该表包含多少列,每列的数据的类型信息,无须指定包含多少行,数据库的行是动态改变的。特殊列被称为主键列。)
三、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)。
四、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 (必须放在最后)
五、回顾JDBC
设置工做空间的编码:
windows->workspace->Text file encoding -> other UTF-8。
建立JavaProject。
JDBC概述:
Java DataBase Connectivity: java 数据库了解。
一、JDBC是一种用于执行SQL语句的Java API;
二、JDBC能够为多种关系数据库提供统一访问入口;
三、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开发步骤:
一、注册驱动
Class.forName("com.mysql.jdbc.Driver");
二、得到链接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/web","root","12345678");
DriverManager.getConnection(url, username, password):三个参数分别是url:jdbc的地址(位置,网址) , username 用户名, password 密码。
三、得到语句执行者
经过Connection对象建立Statement对象。
Statement stmt = conn.createStatement();
四、执行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语句)
五、处理结果
rs.next();
rs.getXxx();
六、释放资源
栈(先进后出):
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注入攻击!!!?表明什么
六、Limit关键字进行查询操做(分页查询)
a、说出limit关键字两个参数的含义
(limit 2, 2) : 第一个2起始位置, 第二个2每页显示的数目
每页显示3条件记录,要查询第3页。
第一参数等于查询的页数减一乘以每页显示的数目,第二个参数是每页显示的数目
select * from product limit 6,3;
b、写出limit关键字查询数据SQL语句
总结:
一、说出JDBC的概念
二、说出JDBC的开发步骤
三、可以使用DriverManager类 (做用,加载驱动方法,获取链接方法)
四、可以使用Connection接口 (做用,获取接口的方法)
五、可以使用Statement接口
六、可以使用ResultSet接口
七、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语法一部分(查询条件,查询结果,表等)
八、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);
}
}
}
注意:一、PreparedStatement的用法。二、释放资源为何要放在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)!
九、使用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);
}
}
十、Java项目读取properties文件的几种方法
1、项目中常常会须要读取配置文件(properties文件),所以读取方法总结以下:
一、经过java.util.Properties读取
Java代码
- Properties p=new Properties();
- //p须要InputStream对象进行读取文件,而获取InputStream有多种方法:
- //一、经过绝对路径:InputStream is=new FileInputStream(filePath);
- //二、经过Class.getResourceAsStream(path);
- //三、经过ClassLoader.getResourceAsStream(path); 经过本身的类加载最妥当!?why?
- p.load(InputStream is);
- is.close();
- p.getString(String(key))
二、经过java.util.ResourceBundle读取
Java代码
- ResourceBundle rb=ResourceBundle.getBundle(packageName);
- rb.getString(String key);
十一、JDBC 链接池&DBUtils
链接池:解决资源浪费,提供代码性能。
本小节目标:
使用DBCP,C3P0链接池完成基本数据库的操做。
使用DBUtils完成CRUD的操做。
数据库链接池的解决方案是:
当应用程序启动时,系统主动创建足够的数据库链接,并将这些链接组成一个链接池。每次应用程序请求数据库链接时,无须从新打开链接,而是从链接池中取出已有的链接使用,使用完后再也不关闭数据库链接,而是直接将链接归还给链接池。经过使用链接池,将大大提升程序的运行效率。
数据库链接池是Connection 对象的工程。数据库链接池的经常使用参数以下。
a、数据库的初始链接数
b、链接池的最大链接数
c、链接池的最小链接数
d、链接池每次增长的容量
公共接口:javax.sql.DataSource。
常见的链接池:DBCP 、 C3P0 (主要)
1、自定义链接池
一、建立链接池实现(数据源),并实现接口javax.sql.DataSource。由于咱们只使用该接口中getConnection()方法。
二、提供一个集合,用于存放链接,由于移除、添加操做过多,因此选择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();
}
}
}