JDBC
数据库驱动:应用程序无法直接连接到数据库,需要一个数据库驱动;
不同的数据库有不同的驱动,这样不利于开发人员对数据库的操作,SUN公司为了简化开发人员对数据库的操作,提供了一个(Java操作数据库的)规范,俗称JDBC,这些规范的实现由具体的厂商去做;
创建一个JDBC程序
- 导入数据库驱动; 导入(mysql-connector-java-5.1.47) jar包, 引入依赖;
- 编写jdbc程序
// 一个jdbc程序
public class JDBCStudy {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");// 加载驱动,固定写法;
// 2. 用户信息和url
//useUnicode=true(支持中文编码)&characterEncoding=utf8(设置字符集)&useSSL=true(使用安全连接) jdbcstudy: 连接的数据库名
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
String username = "root";
String password = "root";
//3.连接数据库,返回数据库对象; Connection 就是数据库对象;
Connection connection = DriverManager.getConnection(url, username, password);
//4.得到执行SQL的对象; Statement 为执行SQL的对象;
Statement statement = connection.createStatement();
//5 . Statement对象去执行SQL语句;
String sql = "select * from user"; //定义一个SQL语句;
ResultSet resultSet = statement.executeQuery(sql);//使用 executeQuery()去执行查询语句, executeUpdate()执行增删改语句;
//返回一个链表形式的结果集,结果集封装了表中的数据信息;
//executeUpdate()执行增删改语句 ,它返回受影响的行数;
//execute()执行任何SQL;
while (resultSet.next()){
System.out.println("id = "+resultSet.getObject("id"));
System.out.println("name = "+resultSet.getObject("name"));
System.out.println("password = "+resultSet.getObject("password")); //通过 getXxx(“字段名”)获取数据
}
//6.释放连接
resultSet.close();
statement.close();
connection.close();
}
}
Statement对象
Statement对象用于向数据库发送SQL语句;
两个方法:
- executeQuery() ; 用于向数据库发送查询语句,返回一个结果集;
- executeUpdata(); 用于向数据库发送增删改语句,返回收影响的行数;
提取工具类
将创建jdbc程序中的一些固定步骤写入一个工具类,使用时直接调用该类方法;
- 创建一个 数据库配置文件(db.properties) ;
# 数据库配置文件
#数据库配置信息 数据库驱动,url,用户名,密码
driver = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
username = root
password = root
- 创建数据库 工具类 ;
//数据库工具类
public class JdbcUtlis {
//定义接收配置文件信息的变量;
private static String driver = null;
private static String url = null;
private static String username = null;
private static String password = null;
static {
try {
//读取配置文件, 通过类加载器,得到配置文件信息;(db.properties)为配置文件名;
InputStream in = JdbcUtlis.class.getClassLoader().getResourceAsStream("db.properties");//读取配置文件,返回一个输入流;
//将流读入properties对象
Properties properties = new Properties(); //创建一个 properties 对象;
properties.load(in); //加载流到properties对象,所有的信息已经被读取到properties对象中;
//从properties对象中获取信息;
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
//1.加载驱动,驱动只用加载一次;
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接的方法;
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, username, password);
}
//释放资源的方法;
public static void release(Connection conn, Statement st,ResultSet re){ //传入数据库对象,执行SQL的对象,结果集对象
if (re!=null){
try {
re.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (st!=null){
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
- 创建jdbc程序;
//使用数据库工具类创建一个jdbc程序
public class JdbcPro {
public static void main(String[] args) {
Connection connection = null; //为了方便关闭,提升作用域;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtlis.getConnection();//获取连接, 直接调用工具类中的静态方法;
statement = connection.createStatement();//创建执行SQL的statement对象;
String sql = "select * from user"; //定义SQL语句;
resultSet = statement.executeQuery(sql); //执行sql
while (resultSet.next()){
System.out.println("id = "+resultSet.getObject("id"));
System.out.println("name = "+resultSet.getObject("name"));
System.out.println("password = "+resultSet.getObject("password"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtlis.release(connection,statement,resultSet);//通过数据库工具类释放连接;
}
}
}
SQL注入
SQL存在漏洞,存在被攻击泄露数据的情况;
SQL会被拼接(or)进而实现一些非法操作;
//sql注入
public class SqlInject {
public static void main(String[] args) throws SQLException {
// 正常登录方式 login("张三","123456");
login("'or'1=1","'or'1=1"); //SQL注入问题,拼接字符串
}
//登录方法
public static void login(String userName, String password) throws SQLException {
Connection connection = JdbcUtlis.getConnection();//得到数据库对象;
Statement statement = connection.createStatement();//得到执行sql的对象;
String sql = "select name,password from user where `name` = '"+userName+"' and `password` = '"+password+"' ";
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()){
System.out.println(resultSet.getString("name"));
System.out.println(resultSet.getString("password"));
}
JdbcUtlis.release(connection,statement,resultSet);
}
}
PreparedStatement对象
PreparedStatement对象可以防止SQL注入,并且效率更高;
public class PreparedSta {
public static void main(String[] args) throws SQLException {
Connection connection = JdbcUtlis.getConnection();
String sql = "select name from user where id = ?";// 使用preparedStatement , 将 值用? 代替;
PreparedStatement preparedStatement = connection.prepareStatement(sql); //使用 preparedStatement()创建需要一个SQL作为参数预编译;
preparedStatement.setInt(1,1);//使用 setXxx()给?赋值,第一个参数为第几个?,第二个为值;
ResultSet resultSet = preparedStatement.executeQuery(); //直接调用方法执行;
while (resultSet.next()){
System.out.println(resultSet.getString("name"));
}
JdbcUtlis.release(connection,preparedStatement,resultSet);
}
}
与Statement的区别:
- 创建PrepareStatement对象需要参数,参数为一个sql; 进行SQL预编译
- sql语句中的值用?代替;
- 通过PrepareStatement中的 setXxx(int index, object value)方法设置?的值; index为?的位置,value为设置的值;
- 执行时 直接调用执行SQL的方法,不需要再传递参数;
PreparedStatement防止SQL注入的本质:把传递进来的参数当作字符, 如果其中有转义字符,会自动忽略。
数据库连接池
池化技术:准备一些预先的资源,过来就连接预先准备好的;
编写连接池,实现一个接口 DataSource
开源数据源实现:DBCP,C3P0
使用了这些数据库连接池之后,我们在项目开发中就不用编写连接数据库的代码;