一、原始JDBC的缺陷及Mybatis解决方式
- JDBC每次操作数据库都会有与数据库连接和释放资源的操作,极大降低了效率——Mybatis采用JDBC连接池
- 原始JDBC将sql语句硬编码到java文件中,不易维护——Mybatis将sql语句写在多个mapper.xml配置文件中,统一管理维护
- 原始JDBC从resutSet中获取结果集数据时存在硬编码,不易维护——Mybatis将结果集映射为一个java对象
二、Mybatis大致工作原理
三、原始DAO开发实例
1、实现功能
- 根据id准确查询学生信息
- 根据姓名模糊查询学生信息
- 增添学生信息
- 修改学生信息
- 根据id删除学生信息
2、创建web工程,引入mybatis基础包及依赖包
完整目录结构为
3、写数据库连接信息DataSource.properities及log4j配置文件log4j.properities
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c:\mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=debug, stdout
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/mybatis_test
jdbc.username=root
jdbc.password=root
4、创建全局配置文件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>
</configuration>
5、在SqlMapConfig.xml中配置数据库连接环境
<properties resource="DataSource.properties"></properties>
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理,事务控制由mybatis-->
<transactionManager type="JDBC" />
<!-- 数据库连接池,由mybatis管理-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
6、创建与数据库结构相同对象的java类Student.java用来与数据库相互的映射
public class Student {
private int id;
private String name;
private String sex;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
7、创建dao接口
public interface StuDao {
public Student findStuById(int id) throws Exception;
public List<Student> findStuByName(String name) throws Exception;
public void addStu(Student Stu) throws Exception;
public void delStu(int id) throws Exception;
public void upStu(Student Stu) throws Exception;
}
8、创建StuMapper.xml,配置statement(Sql语句)
<?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">
<mapper namespace="cn.csdn.mybatis.dao.StuDao">
<select id="findStuById" parameterType="int" resultType="cn.csdn.mybatis.po.Student">
SELECT * FROM Student WHERE id=#{value}
</select>
<select id="findStuByName" parameterType="String" resultType="cn.csdn.mybatis.po.Student">
SELECT * FROM Student WHERE name LIKE '%${value}%'
</select>
<insert id="addStu" parameterType="cn.csdn.mybatis.po.Student" >
INSERT INTO Student(name,sex) VALUE(#{name},#{sex})
</insert>
<delete id="delStu" parameterType="int">
DELETE FROM Student WHERE id = #{value}
</delete>
<update id="upStu" parameterType="cn.csdn.mybatis.po.Student">
UPDATE Student SET name = #{name}, sex = #{sex} where id = #{id}
</update>
</mapper>
9、在SqlMapConfig.xml中配置StuMapper.xml
<mappers>
<mapper resource="mapper/StuMapper.xml"/>
</mappers>
10、写StuDao.java的实现类StuImp.java
public class StuImp implements StuDao{
SqlSessionFactory sqlSessionFactory;
public StuImp(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public Student findStuById(int id) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
Student Stu = sqlSession.selectOne("cn.csdn.mybatis.dao.StuDao.findStuById",id);
sqlSession.close();
return Stu;
}
@Override
public List<Student> findStuByName(String name) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
List<Student> Stus = sqlSession.selectList("cn.csdn.mybatis.dao.StuDao.findStuByName",name);
sqlSession.close();
return Stus;
}
@Override
public void addStu(Student stu) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.insert("cn.csdn.mybatis.dao.StuDao.addStu",stu);
sqlSession.commit();
sqlSession.close();
}
@Override
public void delStu(int id) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.delete("cn.csdn.mybatis.dao.StuDao.delStu",id);
sqlSession.commit();
sqlSession.close();
}
@Override
public void upStu(Student stu) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.update("cn.csdn.mybatis.dao.StuDao.upStu",stu);
sqlSession.commit();
sqlSession.close();
}
}
11、采用JUnit单元测试一个操作:
class StuImpTest {
private SqlSessionFactory sqlSessionFactory;
@BeforeEach
void setUp() throws Exception {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("SqlMapConfig.xml"));
}
@Test
void testFindStuById() throws Exception {
StuImp stuImp = new StuImp(sqlSessionFactory);
Student stu = stuImp.findStuById(1);
System.out.println(stu.toString());
}
}
原始DAO操作数据库功能实现!
四、原始DAO方式总结
StuMapper.xml中
- namespace理论上可以写任何值,但为了与mapper代理的方式对应,此处写dao接口的完整地址
- parameterType:指定输入参数的类型
- resultType:指定输出参数的类型
- #{}:占位符,类似于?,参数为简单类型时括号里的值可任意,一般写#{value}
- ${}:无视格式的字符串拼接符,但会有sql注入的风险,所以不推荐使用,参数为简单类型时,括号里的值必须为value
StuImp.java中
- selectOne:表示查询出一条记录进行映射。如果使用selectOne可以实现使用selectList也可以实现(list中只有一个对象)。
- selectList:表示查询出一个列表(多条记录)进行映射。如果使用selectList查询多条记录,不能使用selectOne。
SqlSession使用范围
- SqlSessionFactoryBuilder:当做一个工具类,创建SqlSessionFactory
- SqlSessionFactory:通过SqlSessionFactory创建SqlSession,使用单例模式管理sqlSessionFactory(工厂一旦创建,使用一个实例)。(上例采用构造的方法注入同一个sqlSessionFactory)
- SqlSession:
- SqlSession是一个面向用户(程序员)的接口。
- SqlSession中提供了很多操作数据库的方法:如:selectOne(返回单个对象)、selectList(返回单个或多个对象)。
- SqlSession是线程不安全的,在SqlSesion实现类中除了有接口中的方法(操作数据库的方法)还有数据域属性。
- SqlSession最佳应用场合在方法体内,定义成局部变量使用。
五、原始DAO操作中存在的问题
- 问题主要存在于dao的实现类中
- 在每一条sql语句的执行中,StuImp.java存在了大量的重传代码,如sqlSession的获得、释放等等。
- 在执行SqlSession.insert()、SqlSession.delete()、SqlSession.update()、SqlSession.select()时,对statement的id硬编码,不易维护;参数的输入使用泛型,不利于在编译阶段发现输入参数不对的问题
——由此,更好的使用Mybatis的方法为Mapper代理方式,满足一定的编写规范,把dao接口的实现(下称为mapper接口)丢给Mybatis**自动处理**。
六、mapper代理方式实例
1、Mybatis使用mapper代理的方式要遵循的规则
- 在mapper.xml中namespace为mapper接口地址。上例已经提过
- mapper接口中的方法名和mapper.xml中statement的id一致
- mapper接口中的方法输入参数类型和mapper.xml中statement的parameterType指定的类型一致。
- mapper接口中的方法返回值类型和mapper.xml中statement的resultType指定的类型一致。
2、上例原始DAO模式的编写中已经符合的上述四点规范,所以不再重新复制代码,1-9步完全一致,不需要第10步创建实现类
3、直接用JUnit测试添加学生:
class StuDaoTest {
private SqlSessionFactory sqlSessionFactory;
@BeforeEach
void setUp() throws Exception {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("SqlMapConfig.xml"));
}
@Test
void testAddStu() throws Exception{
SqlSession sqlSession = sqlSessionFactory.openSession();
StuDao stuDao = sqlSession.getMapper(StuDao.class);//获得代理对象
Student stu = new Student();
stu.setName("小红");
stu.setSex("女");
stuDao.addStu(stu);//需要手动提交
sqlSession.commit();
}
}
mapper代理方式完成,简单高效!