JDBC全称为:Java Data Base Connectivity(java数据库连接),它主要由接口组成。
组成JDBC的2个包:java.sql与javax.sql(这两个包会自动导入)。开发JDBC应用需要以上2个包的支持外,还需要导入相应JDBC的数据库实现(即数据库驱动)。
编写JDBC步骤:
一、搭建实验环境 :
1、在mysql中创建一个库,并创建user表和插入表的数据。
2、新建一个Java工程,并导入数据驱动。
二、编写程序,在程序中加载数据库驱动
三、建立连接(Connection)
四、创建用于向数据库发送SQL的Statement对象,并发送sql
五、从代表结果集的ResultSet中取出数据,打印到命令行窗口
六、断开与数据库的连接,并释放相关资源
例:public class Demo1 {
public static void main(String[] args) throws SQLException {
String url = "jdbc:mysql://localhost:3306/day14";
String username = "root";
String password = "root";
//1.加载驱动
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
//2。获取链接
Connection conn = DriverManager.getConnection(url, username, password);
//3.获取向数据库发sql语句的statament对象
Statement st = conn.createStatement();
//4.向数据库发送sql,获取数据库返回的结果集
ResultSet rs = st.executeQuery("select * from users");
//5.从结果集中获取数据,不考虑类型就全部为object
while(rs.next()){
System.out.println("id=" + rs.getObject("id"));
System.out.println("name=" + rs.getObject("name"));
System.out.println("password=" + rs.getObject("password"));
System.out.println("email=" + rs.getObject("email"));
System.out.println("birthday=" + rs.getObject("birthday"));
}
//6.释放资源(释放链接)资源很稀有,一定要释放
rs.close();
st.close();
conn.close();
}
}
DriverManager对象
程序中的DriverManager用于加载驱动,并创建与数据库的链接
常用方法:DriverManager.registerDriver(new Driver())
DriverManager.getConnection(url, user,password)
注:在实际开发中并不推荐采用registerDriver方法注册驱动。主要原因在于查看Driver的源代码可以看到,如果采用此种方式,会导致驱动程序注册两次,也就是在内存中会有两个Driver对象。另 外程序依赖mysql的api,脱离mysql的jar包,程序将无法编译,将来程序切换底层数据库将会非 常麻烦。
推荐方式:Class.forName(“com.mysql.jdbc.Driver”);
采用此种方式不会导致驱动对象在内存中重复出现,并且采用此种方式,程序仅仅只需要一个字符串,不需要依赖具体的驱动,使程序的灵活性更高。同样,在开发中也不建议采用具体的驱动类型指向getConnection方法返回的connection对象。
数据库URL
格式:jdbc:mysql://localhost:3306/应用名称 ? 参数名:参数值
注:常用的参数useUnicode=true&characterEncoding=UTF-8,为了别的程序也用此应用,或者维护方便建议加上编码参数在数据库URL中
常用数据库URL地址的写法:
Oracle—jdbc:oracle:thin:@localhost:1521:应用名称
SqlServer—jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=应用名称
MySql—jdbc:mysql://localhost:3306/应用名称,简写形式:jdbc:mysql:///应用名称
Connection对象
Jdbc程序中的Connection,它用于代表数据库的链接,Collection是数据库编程中最重要的一个对象,客户端与数据库所有交互都是通过connection对象完成的。
常用方法:createStatement():创建向数据库发送sql的statement对象。
prepareStatement(sql) :创建向数据库发送预编译sql的PrepareSatement对象(用于防止 SQL注入)。
prepareCall(sql):创建执行存储过程的callableStatement对象。
setAutoCommit(boolean autoCommit):设置事务是否自动提交。
commit() :在链接上提交事务。
rollback() :在此链接上回滚事务。
Statement对象
Jdbc程序中的Statement对象用于向数据库发送SQL语句。
常用方法:executeQuery(String sql) :用于向数据发送查询语句。
executeUpdate(String sql):用于向数据库发送insert、update或delete语句
execute(String sql):用于向数据库发送任意sql语句
addBatch(String sql) :把多条sql语句放到一个批处理中。
executeBatch():向数据库发送一批sql语句执行。
ResultSet对象
Jdbc程序中的ResultSet用于代表Sql语句的执行结果。Resultset封装执行结果时,采用的类似于表格 的方式。ResultSet 对象维护了一个指向表格数据行的游标,初始的时候,游标在第一行之前,调用 ResultSet.next()方法,可以使游标指向具体的数据行,进行调用方法获取该行的数据。ResultSet既然 用于封装执行结果的,所以该对象提供的都是用于获取数据的get方法:
获取任意类型的数据
getObject(intindex)
getObject(stringcolumnName)
注:一般最好不直接用object,是什么类型就调用什么类型的方法
获取指定类型的数据
getString(intindex)
getString(StringcolumnName)
ResultSet还提供了对结果集进行滚动的方法:
next():移动到下一行,返回boolean,用于取出所有的值
Previous():移动到前一行
absolute(introw):移动到指定行
beforeFirst():移动resultSet的最前面。
afterLast() :移动到resultSet的最后面。
常用数据类型转换表
用于结果集中获取数据类型
释放资源
Jdbc程序运行完后,切记要释放程序在运行过程中,创建的那些与数据库进行交互的对象,这些对象 通常是ResultSet, Statement和Connection对象。特别是Connection对象,它是非常稀有的资源,用完 后必须马上释放,如果Connection不能及时、正确的关闭,极易导致系统宕机。Connection的使用原 则是尽量晚创建,尽量早的释放。为确保资源释放代码能运行,资源释放代码也一定要放在finally语句中。
以上第一个JDBC程序改进为:
public class Demo2 {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
String url = "jdbc:mysql:///day14";
String username = "root";
String password = "root";
Connection conn = null;
Statement st = null;
ResultSet rs = null;
//为了资源一定能释放,用到try finally
try{
//避免出现两个Driver对象
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(url, username, password);
st = conn.createStatement(); //throw
rs = st.executeQuery("select * from users");
while(rs.next()){
//获取每个值封装到user中,用到各自类型的方法
User user = new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
user.setPassword(rs.getString("password"));
user.setEmail(rs.getString("email"));
user.setBirthday(rs.getDate("birthday"));
}
}finally{
//确保每个资源都被释放(模板释放代码)
if(rs!=null){
try{
rs.close();
}catch (Exception e) {
e.printStackTrace();
}
rs = null;
}
if(st!=null){
try{
st.close();
}catch (Exception e) {
e.printStackTrace();
}
st = null;
}
if(conn!=null){
try{
conn.close();
}catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
JDBC对数据库进行增删改查
Jdbc中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个 对象向数据库发送增删改查语句即可。Statement对象的executeUpdate方法,用于向数据库发送增、 删、改的sql语句,executeUpdate执行完后,将会返回一个整数(即增删改语句导致了数据库几行数据 发生了变化)。Statement.executeQuery方法用于向数据库发送查询语句,executeQuery方法返回代表 查询结果的 ResultSet对象。
例:JDBC对数据库进行增删改查操作演示
db.properties中(如果以后改程序就用直接改配置文件信息就行了)
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/day14
username=root
password=root
JdbcUtils工具类中
public class JdbcUtils {
//为了通用,在配置文件中定义数据库的连接信息
private static Properties config = new Properties();
static{
try {
//用类装载器去读取配置文件
config.load(JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties"));
//注册DriverManager驱动
Class.forName(config.getProperty("driver"));
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
//获取连接
public static Connection getConnection() throws SQLException{
return DriverManager.getConnection(config.getProperty("url"), config.getProperty("username"), config.getProperty("password"));
}
//释放资源
public static void release(Connection conn,Statement st,ResultSet rs){
if(rs!=null){
try{
rs.close(); //throw new
}catch (Exception e) {
e.printStackTrace();
}
rs = null;
}
if(st!=null){
try{
st.close();
}catch (Exception e) {
e.printStackTrace();
}
st = null;
}
if(conn!=null){
try{
conn.close();
}catch (Exception e) {
e.printStackTrace();
}
}
}
}
增删改演示
public class Demo3 {
//插入数据
public void insert() throws SQLException{
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try{
//获取连接
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql = "insert into users(id,name,password,email,birthday) values(4,'eee','123','ee@sina.com','1980-09-09')";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("插入成功!!!");
}
}finally{
JdbcUtils.release(conn, st, rs);
}
}
//增加数据
public void update() throws SQLException{
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql = "update users set name='fff' where id='4'";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("更新成功!!");
}
}finally{
JdbcUtils.release(conn, st, rs);
}
}
//删除数据
public void delete() throws SQLException{
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql = "delete from users where id=4";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("删除成功!!");
}
}finally{
JdbcUtils.release(conn, st, rs);
}
}
//查找数据
public void find() throws SQLException{
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql = "select id,name,password,email,birthday from users where id=1";
//只有查找用到executeQuery方法,增删改用到executeUpdate方法
rs = st.executeQuery(sql);
User user = null;
//只有一条记录就用if就可以了
if(rs.next()){
user = new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
user.setPassword(rs.getString("password"));
user.setEmail(rs.getString("email"));
user.setBirthday(rs.getDate("birthday"));
}
System.out.println(user);
}finally{
JdbcUtils.release(conn, st, rs);
}
}
//获取所以数据
public void getAll() throws SQLException{
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql = "select id,name,password,email,birthday from users";
rs = st.executeQuery(sql);
//定义一个用来存储user对象的集合
List list = new ArrayList();
while(rs.next()){
User user = new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
user.setPassword(rs.getString("password"));
user.setEmail(rs.getString("email"));
user.setBirthday(rs.getDate("birthday"));
list.add(user);
}
System.out.println(list);
}finally{
JdbcUtils.release(conn, st, rs);
}
}
}
注意:在myeclipse中改变了工程名称,一定要在properties的myeclipse—validation—web中也改名称才行。
SQL 注入
SQL注入是用户利用某些系统没有对输入数据进行充分的检查,从而进行恶意破坏的行为。
1、statement存在sql注入攻击问题,例如登陆用户名采用' or 1=1 or username=‘
2、对于防范 SQL 注入,可以采用PreparedStatement取代Statement。
PreparedStatement
PreperedStatement是Statement的子类,它的实例对象可以通过调用Connection.preparedStatement()方法 获得,相对于Statement对象而言:PreperedStatement可以避免SQL注入的问题。Statement会使数据库 频繁编译SQL,可能造成数据库缓冲区溢出。PreparedStatement 可对SQL进行预编译,从而提高数据库 的执行效率。并且PreperedStatement对于sql中的参数,允许使用占位符的形式进行替换,简化sql语句 的编写。
statment和preparedStatement的区别:
1.preparedStatement是statement的孩子
2.preparedStatement可以防止sql注入的问题
3.preparedStatement会对sql语句进行预编译,以减轻数据库服务器的压力
例:public User find(String username, String password) {
Connection conn = null;
PreparedStatement st = null; //PreparedStatment
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
//用占位符替代
String sql = "select * from users where username=? and password=?";
st = conn.prepareStatement(sql); //预编译这条sql
//替换占位符
st.setString(1, username);
st.setString(2, password);
//注意,一定不要传入sql了。
rs = st.executeQuery();
if(rs.next()){
User user = new User();
user.setBirthday(rs.getDate("birthday"));
user.setEmail(rs.getString("email"));
user.setId(rs.getString("id"));
user.setNickname(rs.getString("nickname"));
user.setPassword(rs.getString("password"));
user.setUsername(rs.getString("username"));
return user;
}
return null;
}catch (Exception e) {
throw new DaoException(e);
}finally{
JdbcUtils.release(conn, st, rs);
}
}