首先给出直接通过传统的JDBC访问数据库实例
import java.sql.*;
/**
* Created by hsc on 16/8/27.
*/
public class JdbcTest {
private static final String DRIVER = "com.mysql.jdbc.Driver";
private static String userName = "test"; //连接数据库用户名
private static String password = "test123";//连接数据库的密码
private static String connectionUrl = "jdbc:mysql://IP地址:端口/数据库名";
public static void queryTest(String sql, Object[] params){
//数据库的连接
Connection connection = null;
ResultSet resultSet = null;
//预编译的Statement 向数据库发送sql语句,数据库那边进行编译,数据那边将编译结果存放在缓存
PreparedStatement preparedStatement = null;
try {
Class.forName(JdbcTest.DRIVER);
connection = DriverManager.getConnection(connectionUrl, userName, password);
preparedStatement = connection.prepareStatement(sql);
// 参数赋值,向占位符中填充数据
if (params != null) {
for (int i = 0; i < params.length; i++) {
preparedStatement.setObject(i + 1, params[i]);
}
}
resultSet = preparedStatement.executeQuery();
//遍历查询结果集
while (resultSet.next()) {
System.out.println(resultSet.getString(1));
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
//释放资源
} finally {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
public static void main(String args[]) {
//问号表示占位符
String querySql = "select * from st_didinfo limit ?";
Object[] objects = new Object[1];
objects[0] = 5;
queryTest(querySql, objects);
}
}
从上面的程序不难发现有以下问题
1.使用时候创建,不使用的时候立即释放,对数据库进行频繁的连接和开启,造成了数据库资源的浪费,影响数据库的性能
2.将sql语句硬编码()到java代码中,如果sql语句修改,需要重新编译java代码,不利于系统的维护
设想:如果能将sql语句配置在文件中,即使sql变化了,也不需要对java代码进行重新编译。
3.向PreparedStatement设置参数,对占位符把控设置和设置参数值,硬编码在java中利于系统的维护
4.从resultSet中遍历数据结果时候,存在硬编码,将表字段进行硬编码,不利于系统维护
Mybatis是持久层框架,是和数据库打交道的框架,
让程序员主要精力放在sql上,通过mybaits提供映射方式,自由灵活生成满足需要的sql语句。
mybaits 可以将PreparedStatement中输入参数自动进行输入映射,将查询结果集灵活的映射成java对象(输出对象)
mybatis开发dao两种方法
1.原始的dao开发(程序需要编写dao接口和dao实现类)
2.mybatis的mapper接口(相当于到接口)代理开发方法
原始的dao开发:
流程图
SqlMapConfig.xml 配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 加载属性文件 -->
<properties resource="db.properties">
<!--properties中还可以配置一些属性名和属性值 正常测试和异常测试
-->
<!-- <property name="jdbc.driver" value=""/> 在元素体内首先读取的,然后会读取resource 或者url加载的属性,他会覆盖-->
</properties>
<!-- 全局配置参数,需要时再设置 可能需要调整一些比如开启二级缓存,延迟加载 -->
<!-- <settings>
</settings> -->
<!-- 别名定义 -->
<typeAliases>
<!-- 针对单个别名定义
type:类型的路径
alias:别名
方便后面sql输入输出映射的使用
-->
<!-- <typeAlias type="com.mybatis.pojo.UserInfo" alias="userInfo"/> -->
<!-- 批量别名定义
指定包名,mybatis自动扫描包中的po类,自动定义别名,别名就是类名(首字母大写或小写都可以)
-->
<package name="com.mybatis.pojo"/>
</typeAliases>
<!--TypeHandler 类型处理器 java类型到JDBC类型转换-->
<!-- 和spring整合后 environments配置将废除-->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理,事务控制由mybatis-->
<transactionManager type="JDBC" />
<!-- 数据库连接池,由mybatis管理-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!-- 加载 映射文件 -->
<mappers>
<mapper resource="sqlmap/UserInfo.xml"/>
</mappers>
</configuration>
UserInfo.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace命名空间,作用就是对sql进行分类化管理,理解sql隔离
注意:使用mapper代理方法开发,namespace有特殊重要的作用
ORM java 对象和关系(数据库的)进行映射
-->
<mapper namespace="test">
<!--id是一个标识,用于开发程序使用 将sql语句封装到mappedStatement对象中,所以将id称为statement的id-->
<!--#{}表示一个占位符号-->
<!--#{id}:其中的id表示接收输入 的参数,参数名称就是id,如果输入 参数是简单类型,#{}中的参数名可以任意,可以value或其它名称-->
<!--resultType:指定sql输出结果 的所映射的java对象类型,select指定resultType表示将单条记录映射成的java对象。-->
<select id="findUserInfoById" parameterType="java.lang.Integer" resultType="com.mybatis.pojo.UserInfo">
SELECT * FROM UserInfo WHERE id=#{value}
</select>
<!-- 根据用户名称模糊查询用户信息,可能返回多条
resultType:指定就是单条记录所映射的java对象 类型
${}:表示拼接sql串,将接收到参数的内容不加任何修饰拼接在sql中。
使用${}拼接sql,引起 sql注入
${value}:接收输入 参数的内容,如果传入类型是简单类型,${}中只能使用value
-->
<select id="findUserByName" parameterType="java.lang.String" resultType="com.mybatis.pojo.UserInfo">
SELECT * FROM UserInfo WHERE userName LIKE '%${value}%'
</select>
<!-- 添加用户
parameterType:指定输入 参数类型是pojo(包括 用户信息)
#{}中指定pojo的属性名,接收到pojo对象的属性值,mybatis通过OGNL获取对象的属性值
-->
<insert id="insertUserInfo" parameterType="com.mybatis.pojo.UserInfo">
<!--
将插入数据的主键返回,返回到user对象中
SELECT LAST_INSERT_ID():得到刚insert进去记录的主键值,只适用与自增主键
keyProperty:将查询到主键值设置到parameterType指定的对象的哪个属性
order:SELECT LAST_INSERT_ID()执行顺序,相对于insert语句来说它的执行顺序
resultType:指定SELECT LAST_INSERT_ID()的结果类型
-->
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
SELECT LAST_INSERT_ID()
</selectKey>
insert into UserInfo(userName,age) value(#{userName},#{age})
<!--
使用mysql的uuid()生成主键
执行过程:
首先通过uuid()得到主键,将主键设置到user对象的id属性中
其次在insert执行时,从userInfo对象中取出id属性值
-->
<!-- <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
SELECT uuid()
</selectKey>
insert into UserInfo(userName,age) value(#{userName},#{age}) -->
</insert>
<!-- 删除 用户
根据id删除用户,需要输入 id值
-->
<delete id="deleteUserInfoById" parameterType="int">
delete from UserInfo where id=#{id}
</delete>
<!-- 根据id更新用户
分析:
需要传入用户的id
需要传入用户的更新信息
parameterType指定userInfo对象,包括 id和更新信息,注意:id必须存在
#{id}:从输入 user对象中获取id属性值
-->
<update id="updateUserInfo" parameterType="userInfo">
update UserInfo set userName=#{userName},age=#{age}
where id=#{id}
</update>
</mapper>
UserInfoDao 接口类
package com.mybatis.dao;
import com.mybatis.pojo.UserInfo;
import java.util.Map;
/**
* Created by hsc on 16/9/4.
*/
public interface UserInfoDao {
public UserInfo findUserInfoById(int id) throws Exception;
public int inserUserInfo(UserInfo userInfo) throws Exception;
public int deleteUserInfoById(int id);
public int updateUserInfo(UserInfo userInfo);
}
UserInfoDao 接口实现类
package com.mybatis.dao.Impl;
import com.mybatis.dao.UserInfoDao;
import com.mybatis.pojo.UserInfo;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import java.util.Map;
/**
* Created by hsc on 16/9/4.
*/
public class UserInfoDaoImpl implements UserInfoDao {
private SqlSessionFactory sqlSessionFactory;
public UserInfoDaoImpl(SqlSessionFactory sqlSessionFactory)
{
this.sqlSessionFactory=sqlSessionFactory;
}
public UserInfo findUserInfoById(int id) throws Exception {
SqlSession sqlSession=sqlSessionFactory.openSession();
UserInfo userInfo= sqlSession.selectOne("test.findUserInfoById",id);
sqlSession.close();
return userInfo;
}
public int inserUserInfo(UserInfo userInfo) throws Exception {
SqlSession sqlSession=sqlSessionFactory.openSession();
int size= sqlSession.insert("test.insertUserInfo",userInfo);
sqlSession.commit();//插入要做提交
sqlSession.close();
return size;
}
public int deleteUserInfoById(int id) {
SqlSession sqlSession=sqlSessionFactory.openSession();
int size= sqlSession.delete("test.deleteUserInfoById",id);
sqlSession.commit();//删除要做提交
sqlSession.close();
return size;
}
public int updateUserInfo(UserInfo userInfo) {
SqlSession sqlSession=sqlSessionFactory.openSession();
int size= sqlSession.delete("test.updateUserInfo",userInfo);
sqlSession.commit();//更新要做提交
sqlSession.close();
return size;
}
}
单元测试类
package com.mybatis.Test;
import com.mybatis.dao.Impl.UserInfoDaoImpl;
import com.mybatis.dao.UserInfoDao;
import com.mybatis.pojo.UserInfo;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
/**
* Created by hsc on 16/9/4.
*/
public class UserInfoDaoTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void initSqlFactory() throws Exception
{
String res="SqlMapConfig.xml";
InputStream in= Resources.getResourceAsStream(res);
//创建会话工厂
sqlSessionFactory=new SqlSessionFactoryBuilder().build(in);
}
@Test
public void testFindUserInfoById() throws Exception
{
UserInfoDao userInfoDao=new UserInfoDaoImpl(sqlSessionFactory);
UserInfo userInfo=userInfoDao.findUserInfoById(1);
System.out.println(userInfo.getUserName());
}
@Test
public void testDeleteUserInfoById() throws Exception
{
UserInfoDao userInfoDao=new UserInfoDaoImpl(sqlSessionFactory);
int size=userInfoDao.deleteUserInfoById(1);
System.out.println(size);
}
@Test
public void testInsertUserInfo() throws Exception
{
UserInfoDao userInfoDao=new UserInfoDaoImpl(sqlSessionFactory);
UserInfo userInfo=new UserInfo();
userInfo.setAge(18);
userInfo.setUserName("张大雷");
int size=userInfoDao.inserUserInfo(userInfo);
System.out.println(size);
System.out.println(userInfo.getId());
}
@Test
public void testUpateUserInfo() throws Exception
{
UserInfoDao userInfoDao=new UserInfoDaoImpl(sqlSessionFactory);
UserInfo userInfo=new UserInfo();
userInfo.setAge(14);
userInfo.setUserName("陈大雷");
userInfo.setId(6);
int size=userInfoDao.updateUserInfo(userInfo);
System.out.println(size);
}
}
原始dao开发方法(程序员需要写dao接口和实现类,需要向dao的实现类注入SqlSessionFactory,它是单例,是线程安全的
SqlSession 是线程不安全的,最佳应用场合是方法体内
总结原始dao开发的问题1.dao 接口实现类中存在大量模板或者重复的代码 2.依然存在硬编码
参考资料:传智燕青的课堂笔记