Java JDBC拓展
上接Java JDBC来接MySql基础语法:https://mp.csdn.net/postedit/83831745
(1)JDBC框架技术
①POJO:Plain Ordinary Java Object(简单Java对象)
POJO其实就是JavaBean
POJO中规定类中有:
private成员变量(用包装类Integer、Boolean、Long、String、Double等)
public构造方法(可以不写)
public对应的Setter/Getter方法
说明:POJO概念的引入是为了便于对数据表中的元祖(一行数据)进行包装处理,使用包装类的原因的便于切合数据表中的NULL元素,毕竟基本数据类型是没有NULL这一说的。
i、POJO自动reflection
//1、根据列标题,找到对应的方法
public static Method findMethod(Class cls, String label)
{
// "name" -> "setName()"
char firstChar = Character.toUpperCase(label.charAt(0));
StringBuffer strbuf = new StringBuffer("set" + label);
strbuf.setCharAt(3, firstChar);
// 取得对应的Method
String methodName = strbuf.toString();
Method[] methods = cls.getMethods();
for (Method m : methods)
{
if (m.getName().equals(methodName))
{
return m;
}
}
return null;
}
//2、根据列标题,找到对应的方法组
public static Method[] findMethod(Class cls, String[] labels)
{
Method[] methods = new Method[ labels.length ];
for(int i=0; i<labels.length; i++)
{
methods[i] = findMethod(cls, labels[i]);
}
return methods;
}
//3、调用set方法将数据存入POJO中
public static void map(Object pojo, Method method,
int columnType,
String columnValue) throws Exception
{
if(method == null) return;
if(columnValue == null) return;
// 根据类型,传递合适的参数给setter
Object arg0 = null;
if(columnType == Types.CHAR || columnType == Types.VARCHAR )
{
arg0 = columnValue; // 给方法传一个String参数
}
else if(columnType == Types.BIT) // tinyint(1)
{
arg0 = (columnValue.equals("1"));
}
else if(columnType == Types.DATE) // date
{
arg0 = sdf_d.parse(columnValue);
}
else if(columnType == Types.TIME) // time
{
arg0 = sdf_t.parse(columnValue);
}
else if(columnType == Types.TIMESTAMP) // datetime timestamp
{
arg0 = sdf_dt.parse(columnValue);
}
else if(columnType == Types.TINYINT || columnType == Types.SMALLINT
|| columnType == Types.INTEGER || columnType == Types.BIGINT
|| columnType == Types.DOUBLE || columnType == Types.FLOAT)
{
// 整数类型的处理
Class[] parameterTypes = method.getParameterTypes();
Class c = parameterTypes[0];
if(c.equals( int.class) || c.equals(Integer.class))
{
arg0 = Integer.valueOf(columnValue);
}
else if(c.equals( long.class) || c.equals(Long.class))
{
arg0 = Long.valueOf(columnValue);
}
else if(c.equals( short.class) || c.equals(Short.class))
{
arg0 = Short.valueOf(columnValue);
}
else if(c.equals( byte.class) || c.equals(Byte.class))
{
arg0 = Byte.valueOf(columnValue);
}
else if(c.equals( float.class) || c.equals(Float.class))
{
arg0 = Float.valueOf(columnValue);
}
else if(c.equals( double.class) || c.equals(Double.class))
{
arg0 = Double.valueOf(columnValue);
}
}
// 调用setter方法
Object args[] = { arg0 };
try {
method.invoke(pojo, args);
}catch(IllegalArgumentException e)
{
Class[] parameterTypes = method.getParameterTypes();
Class c = parameterTypes[0];
//System.out.println("期望类型:" + c.getCanonicalName() + ",
实际类型:" + arg0.getClass().getCanonicalName() );
}
说明:从数据表中将元祖信息自动映射到实体类中来。(查询数据表并读取出元祖)
ii、POJO手动reflection
1.XML方式映射
2.注解方式映射
说明:利用配置文件或注解的方法为了实现将实体类(具体的对象)中的数据全部写入到数据库中对应的表中,构成一行数据(元祖)。(向数据表中插入元祖)
(2)JDBC连接池
①基础知识
MySQL连接数:指客户端发起的网络连接的数量
查看最大连接数 (my.ini中设置)
SHOW VARIABLES LIKE 'max_connections'
查看当前连接
SHOW STATUS LIKE 'Threads%' /* 连接数量 */
SHOW processlist /* 连接详情 */
SHOW full processlist
两种连接方式(短连接/长连接):
短连接:每次都要先连接,再操作,最后关闭。(允许并发;耗费资源,效率低)
长连接:一直建立一条连接,每次要用时直接调用这条连接,操作完后不关闭次连接供其他用户调用。(不允许并发;节省资源,效率高)
商业级数据库连接技术:连接池
连接池:提前建立了多条连接,供用户来连接,这些连接仿佛在池子中供用户来取,当用户一时间取很多的时候,连接池中连接的个数增多,但不超过设定的最大连接数;当用户一段时间取较少的时候,连接池中连接的个数减少,但不少于设定的最小连接数。当然这其中肯定还包含很多的优化算法,这里我们就不做深层的讨论了。使用连接池可以让数据库资源使用效率高、支持并发,一般商业级的连接池采用c3p0
C3p0官网:http://www.mchange.com/projects/c3p0/
(3)c3p0连接池技术
配置:把对应的jar包包含进eclipse中,并创建一个c3p0-config.xml文件来做默认配置
//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://127.0.0.1/af_school</property>
<property name="user">root</property>
<property name="password">a1b2c3</property>
<property name="initialPoolSize">5</property> <!—初始连接数 -->
<property name="minPoolSize">2</property> <!—最小连接数 -->
<property name="maxPoolSize">10</property> <!—最大连接数 -->
<!—连接的最大空闲时间,如果超过这个时间,某个数据库连接还没有被使用,则会断开掉这个连接如;果为0,则永远不会断开连接 -->
<property name="maxIdleTime">30</property>
<!--池中数据连接不够时一次增长多少个-->
<property name="acquireIncrement">5</property>
</default-config>
</c3p0-config>
//eclipse测试
// 一个DataSource指代一个数据源, 内部有一个连接池
ComboPooledDataSource cpds = new ComboPooledDataSource();
// 一个Connection代表一次访问
Connection conn = cpds.getConnection();
// 查询操作
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM student");
while(rs.next())
{
// 取出这一行记录
int id = rs.getInt("id");
String name = rs.getString("name");
String phone = rs.getString("phone"); // 可能为null
Date birthday = rs.getDate("birthday");
System.out.println(id + "\t" + name + "\t" + phone );
}
conn.close(); // 连接放回池子(并没有真正释放连接)
cpds.close(); // 数据源如果关闭,相应的池子也就销毁了(特定时候关闭)
注:关闭连接池数据源就与普通数据库连接一样了,甚至更加耗费资源、低效
(4)防止SQL注入
SQL注入:
sql注入是通过人为的利用sql语句,让输入的用户名或密码与代码设计的sql语句结合后构成WHERE判断永真等情况,使得个人账户信息变的及其容易破解,sql注入是数据库代码设计中必须解决的问题,有效的处理sql注入可以使得个人账户信息安全度更高,更有效的保护用户的个人隐私,防止不法分子利用个人信息或虚拟货币违法犯罪。
解决方法:引入转义符
我们知道MYSQL的sql语句中 ’ (单引号) 、` (反引号)等是种特殊字符,这种特殊字符很容易对sql语句进行改写,所以必须要处理这些特殊字符,最常见的方法就是利用转义符来是这种特殊字符成为普通字符就OK了。
以下是利用String.replace( )方法实现特殊字符转义
password=password.replace(" ' ", " /' ");
password=password.replace(" ` ", " /` ");
提升篇
欢迎阅读Hibernate框架篇,Hibernate是对JDBC的优秀全自动封装。
Hibernate入门学习链接:https://blog.csdn.net/biggerchong/article/details/84229658
------谢谢阅读!欢迎评论! -----知飞翀