Jdbc
JDBC: Java DB(数据库) Connection (collection)(连接)
作用:介于应用程序和DB之间的一个桥梁。
JDBC: 是SUN公司定义的一组接口(标准),由各个数据库厂商(mysql、oralce等)去实现该接口(以jar文件)
什么是jar文件: 是java的一种打包文件(压缩)脱离java环境实现重用。
Jar的本质是对JDK的扩展
jdbc的构成:
1:接口:
Connection: 接口负责连接数据库
PreparedStatement->Statement: 负责执行SQL的
ReslutSet: 结果集
2:驱动管理类: DriverManger: 负责加载驱动(导入jar)
3:各个数据库厂商的实现(jar包)
jdbc的使用(重点)
Connection 创建
第一种
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class Test {
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection connection =
// DriverManager.getConnection("jdbc:mysql://localhost:3306/db_2206?serverTimezone=UTC", "数据库账号", "数据库密码");
DriverManager.getConnection("jdbc:mysql:///db_2206?serverTimezone=UTC", "数据库账号", "数据库密码");
System.out.println(connection);//输出连接对象的地址
System.out.println(connection.getCatalog());//数据库的名称
} catch (ClassNotFoundException e) {
System.out.println("未获取驱动"+e.getMessage());
} catch (SQLException e) {
System.out.println("未获取连接"+e.getMessage());
}
}
}
第二种
jdbc.properties
jdbc.username=数据库账号 |
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
import java.util.ResourceBundle;
public class Test3 {
private static final Properties properties =new Properties();
private static String USER;
private static String PWD;
private static String DRIVER;
private static String URL;
private static Connection connection;
static{
ResourceBundle rb=ResourceBundle.getBundle("jdbc");
USER= rb.getString("jdbc.username");
PWD= rb.getString("jdbc.password");
URL= rb.getString("jdbc.url");
DRIVER= rb.getString("jdbc.driver");
try {
Class.forName(DRIVER);
connection= DriverManager.getConnection(URL, USER, PWD);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
// System.out.println(USER);
// System.out.println(URL);
// System.out.println(PWD);
// System.out.println(DRIVER);
}
public static void main(String[] args) {
System.out.println(connection);
}
}
Statement 和PreparedStatement
Statement
//创建执行对象
Statement stmt= connection.createStatement();
//执行sql操作
// boolean b = stmt.execute("create DataBase ttt");
// boolean b = stmt.execute("drop DataBase ttt");
//boolean b = stmt.execute("CREATE TABLE tab_1(id int,age int)");
// int m= stmt.executeUpdate("delete from tab_1 where id=3");
// System.out.println(m);
// boolean b = stmt.execute("update tab_1 set age=20 where id=1");
// stmt.execute("SELECT * FROM tab_1");
ResultSet resultSet = stmt.executeQuery("select * from tab_1");
while(resultSet.next()){//判断是否存在(next)下一个数据
// System.out.println("id:"+resultSet.getInt(2));
// System.out.println("age:"+resultSet.getInt(1));
System.out.println(resultSet.getInt("age"));
System.out.println(resultSet.getInt("id"));
}
stmt.close();
connection.close();
Statement 对象的方法:
方法名 | 参数 | 返回值 | 作用 |
Execute() | sql语句 | Boolean根据执行结果确定true还是false | 执行DDL DML和DQL |
executeUpdate | DML | int (受影响的行数) | 执行增、删、改 |
executeQuery | DQL | ResultSet | 执行查询并返回Result |
ResultSet(结果集对象)
方法名 | 参数 | 返回值 | 作用 |
next() | 无 | Boolean | 判断是否存在下一个记录,同时指向下一个记录 |
get**(索引) | Int | Objet | 根据参数获取sql语句中对应的列的值。 |
get**(“名称”) | String | Object | 根据参数名获取指定列的值。推荐使用 |
注意:
各个对象的创建关系:
1:Connection是通过DriverManager来创建
2:Statment是通过Connection来创建
3:ResultSet通过Statement创建
PreparedStatement
Jdbc中提供了PreparedStatement接口(继承了Statement)通过?传值。
SQL 语句被预编译并存储在 PreparedStatement 对象中。然后可以使用此对象多次高效地执行该语句。
setObject(?的索引:从1开始,值);
可变参数的本质是数组。
JDBC的批量操作
Jdbc的批量操作
1:设置Connection的提交方式为手动提交: setAutoCommit(false)
2:要多次执行的sql语句 addBatch();
3:executeBacth() ---> int[]
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Random;
public class TestBatch {
private static String[] fnames={"赵","钱","孙","李","周","吴","郑","王","冯","陈","储","魏"};
private static String[] lnames={"狗剩","翠花","秋红","建国","建业","大力","国胜","丽丽","旺财"};
public static void main(String[] args) {
Connection connection=null;
PreparedStatement pst=null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql:///db_2206?serverTimezone=GMT%2B8", "root", "root");
//批量添加
connection.setAutoCommit(false);//设置是否是手动提交事务
pst=connection.prepareStatement("insert into person(name,sex) values(?,?)");
Random random =new Random();
for(int i=1;i<=100;i++){
pst.setObject(1, fnames[random.nextInt(fnames.length)]+lnames[random.nextInt(lnames.length)]);
pst.setObject(2, i%2==0 ? 0: 1);
pst.addBatch();//添加到session(缓存)
if(i%10 == 0) {
int[] ints = pst.executeBatch();//批量执行
System.out.println("批量执行了"+ints.length+"次");
}
}
connection.commit();
} catch (ClassNotFoundException | SQLException e) {
if(connection!=null){
try {
connection.rollback();//回滚
} catch (SQLException ex) {
ex.printStackTrace();
}
}
}
}
}
JDBC的事务操作
什么是事务:把一组sql作为一个整体执行,要么都成功,要么都失败。
事务的特性:
A 原子性:事务是不能拆分的。
C 一致性:事务执行前后的数据应一致
I 隔离性:每个事务不能影响其它事务
D 永久性:事务执行前后数据都永久的保存到数据库中。
JDBC操作事务的步骤:
1: 设置Connection的提交方式为手动提交: setAutoCommit(false)
2: 在try代码块中执行事务,如果成功则 commit
3: 在catch代码块中,回滚事务 rollback
JDBC的事务的操作:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TestACID {
public static void main(String[] args) {
Connection connection=null;
PreparedStatement pst1=null,pst2=null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
connection= DriverManager.getConnection("jdbc:mysql:///db_2206?serverTimezone=GMT%2B8", "root", "root");
connection.setAutoCommit(false);//设置是否是手动提交事务
String sql1="update band_card set balance= balance+2500 where card='1101'";
String sql2="update band_card set balance= balance-2500 where card='1102'";
pst1=connection.prepareStatement(sql1);
pst2=connection.prepareStatement(sql2);
int m=pst1.executeUpdate();
int n=pst2.executeUpdate();
System.out.println(m);
System.out.println(n);
connection.commit();
} catch (ClassNotFoundException | SQLException e) {
System.out.println("转账失败!");
try {
if(connection!=null) {
connection.rollback();
}
} catch (SQLException ex) {
ex.printStackTrace();
}
}
}
}
xml
定义:eXtendsable(可扩展) Markup(标签) Language( 语言)
作用: 使用xml文件进行数据的描述和存储:达到规范,方便查看
特点(注意事项):
一个xml文件有且只能有一个根节点:
每个节点都成对出现: <></>
Xml大小写敏感 <name><Name>
过程:
读取xml: IO流: 创建流 读取 关闭
使用dom4j 完成读取: 需要导入dom4j.jar
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.util.List;
public class Test1 {
public static void main(String[] args) throws DocumentException {
//dom4j读取xml文件
//创建流
SAXReader reader = new SAXReader();
//读取xml文件并返回一个Document对象
Document doc = reader.read("src/users.xml");
//通过文档对象获取根节点
Element root = doc.getRootElement();
//System.out.println(root.getName());
//获取根节点的所有子节点的集合
List<Element> list = root.elements();
//System.out.println(list.size());
for(Element element: list){ //遍历<Users>
//System.out.println(element.getName());
//获取各个user的子节点:
List<Element> list1 = element.elements();
for(Element el1 : list1){ //遍历user :name sex aage
System.out.println(el1.getName()+"--->"+el1.getTextTrim());
}
}
}
}
使用xml和map实现sql和java的解耦和
Sql-mapper.xml
<?xml version="1.0" encoding="UTF-8"?> |
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class SqlMapper {
private static Map<String,String> map=new HashMap<String,String>();
static{
SAXReader reader =new SAXReader();
Document doc = null;
try {
doc = reader.read(Thread.currentThread()
.getContextClassLoader().getResourceAsStream("sql-mapper.xml"));
Element root=doc.getRootElement();
List<Element> list= root.elements();
for(Element element:list){
String id = element.attributeValue("id");
String value= element.getTextTrim();
//System.out.println("id:"+id+"...sql:"+value);
map.put(id, value);
}
} catch (DocumentException e) {
e.printStackTrace();
}
}
public static String getSql(String key){
return map.get(key);
}
public static void main(String[] args) throws DocumentException {
String sql= SqlMapper.getSql("delete");
System.out.println(sql);
}
}
反射
定义:程序运行时,动态的获取(修改)类的属性、方法、构造器等,调用方法的一种机制。
通俗的讲: 通过类来得到对象,反射通过对象映射出类。
反射的目的: 通过反射提高代码的灵活性。
反射的三种方式:
//第一种:Class.forName(“包名.类名”) Class<?> c1 = Class.forName("java.lang.Integer"); //第二种: 类名.class //第三种: 对象.getClass(); |
Class.forName()这种方式可以实现延缓类(的创建)
类.class :该类必须存在,但是不需要得到对象(无需对象的属性的默认值)
对象名.getClass(); 对象已经完成了实例化(属性有默认值)
以上的三种方式,前两种使用比较多。
使用:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class TestUser {
public static final int m1=11;
public final static int m2=11;
static public final int m3=11;
final static public int m4=11;
static final public int m5=11;
public static void main(String[] args) {
try {
Class<?> c = Class.forName("com.song.pm.User");
System.out.println("User的属性有:");
Field[] fields = c.getDeclaredFields();
for(Field field: fields){
System.out.println("名称:"+field.getName()+"访问修饰符:"+
Modifier.toString(field.getModifiers())+"---int:"+ field.getModifiers());
}
System.out.println("User的方法:");
Method[] methods = c.getDeclaredMethods();
for(Method method: methods){
System.out.println("方法名:"+method.getName()+
"访问修饰符:"+Modifier.toString(method.getModifiers()));
}
System.out.println("User的构造器");
Constructor<?>[] constructors = c.getDeclaredConstructors();
for(Constructor cc : constructors){
System.out.println("构造器名:"+cc.getName()+
",访问修饰符"+Modifier.toString(cc.getModifiers()));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
注意:
getDeclaredFields() -->返回本类的所有级别的属性
getFields() --> 返回本类和父类的public级别的属性(包括static)
getMethods(); 返回本类和父类的所有public级别的方法(包括static)
getDeclaredMethods(); 返回本类的所有级别的方法
反射的优点:增加代码的灵活性
反射的缺点:
1:效率低(相对于直接new对象方式,编译器)
2:安全性(可以访问私有成员)
3:过多使用反射会导致逻辑混乱
反射的应用场景:框架(通用的操作)
自定义框架!(含金量高)-- > 反射、xml、集合、接口、编程思想(设计模式)
操作:
Class<User> userClass = User.class; 以上代码如果User没有默认构造则引发一下的异常:(没有默认构造)。养成为类手动添加带参构造时,手动把默认构造也写出来。 |
操作属性:
//演示反射如何操作属性:后期作为动态操作表的字段(列)的基础
Class<User> userClass = User.class;
User user = userClass.newInstance();
//获取要操作的属性(根据名称)
Field field = userClass.getDeclaredField("a");
//打开访问开关:
field.setAccessible(true);
//获取属性的值
System.out.println("属性:"+field.getName()+"的值:"+field.get(user));
//修改属性的值
field.set(user, 100);
System.out.println("修改后的a的值是:"+field.get(user));
调用无参无返回值方法:
//得到User类
Class<User> userClass = User.class;
//使用默认构造创建对象(得到User的实例)
User user = userClass.newInstance();
//根据名称获取一个方法(对象)
Method show = userClass.getDeclaredMethod("show");
//打开访问私有方法的开关
show.setAccessible(true);
//调用方法: 普通:对象名.方法名 反射: 方法名.invoke(对象)
show.invoke(user);
调用有参无返回值和有参有返回值:
Class<User> userClass = User.class;
//使用默认构造创建对象(得到User的实例)
User user = userClass.newInstance();
//根据名称获取一个方法(对象)
Method disp = userClass.getDeclaredMethod("disp", String.class);
//打开访问私有方法的开关
disp.setAccessible(true);
//调用方法: 普通:对象名.方法名 反射: 方法名.invoke(对象)
disp.invoke(user,"你好");
Class<User> userClass = User.class;
User user = userClass.newInstance();
//根据名称获取方法
Method sum = userClass.getDeclaredMethod("sum", int.class, float.class);
// System.out.println(sum.invoke(user, 3, 4.5f));
Object obj = sum.invoke(user, 2, 5.3f);
System.out.println(obj);
使用带参构造创建对象:
Class<Dog> dogClass = Dog.class;
//默认构造创建对象
Dog dog = dogClass.newInstance();
System.out.println(dog);
//带参构造
Dog dog1 = dogClass.getDeclaredConstructor(String.class, int.class)
.newInstance("贝贝", 2);
System.out.println(dog1);