【看懂这篇博客需要对mybatis框架的基础知识有所了解】
写在前头:
【本博客使用的Java IDE开发环境并不是myeclipse或者eclipse而是IDEA,在这篇博客所要讲解的知识上两者没有太多的不同,不会因为没有接触过IDEA开发环境而对此篇博客一头雾水,请大家放心阅读。】
【本篇博客使用mybatis框架并不是通过手动导入jar包的方式,而是通过maven完成的jar包的导入】
目录
使用mybatis开发dao的方式和步骤:
1.使用IDEA创建一个maven工程(大家完全可以通过手动导入jar包的方式使用mybatis)
(这里创建maven工程大家可以理解成目的就是为了方便导入jar包,它和平时创建的工程没有什么区别,如果不了解maven的可以百度或者B站去学习一下。)然后将mybatis框架以及数据库驱动所需要的jar包的依赖全部都写在pom.xml中,这次用到的有如下这么多:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--mybatis核心包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.4</version>
</dependency>
<!-- 日志文件管理包 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--生成po、mapper.java、mapper.xml核心jar-->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.6</version>
</dependency>
2.在src目录下创建一个名为SqlMapConfig.xml的xml文件
如果在"new"的时候没有发现xml文件,就自己创建一个 具体方法如下:
点击 + 按钮,即第一步完成后,会出现以下页面:
输入xml之后,就可以进行上图的第二步和第三步了。
3.配置SqlMapConfig.xml文件中的内容
直接对下面的代码进行复制粘贴过去即可(不要紧张,文件头处的代码程序员也写不出来,也不需要程序员写,现在就先用复制粘贴完成这个操作就好,这个并不是学习mybatis的重点所在):
<?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>
接下来就是在<configuration>中配置mybatis的运行环境等信息,这些是重要的(至少要做到可以看懂,有JDBC基础的话看参数就直接可以猜得出每个标签用来做什么 这段代码也直接复制粘贴过去就好):
<configuration>
<!--
environments指整个的运行环境
-->
<environments default="development">
<environment id="development">
<!--使用jdbc事务管理 事物的控制由mybatis完成-->
<transactionManager type="JDBC"></transactionManager>
<!--数据库连接池 由mybatis管理-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatisdemo"/>
<property name="username" value="root"/>
<property name="password" value="admin"/>
</dataSource>
</environment>
</environments>
<!--加载映射文件-->
</configuration>
4.创建表所对应的类的映射文件
以下是所用数据库和数据库中的表结构
user表(即用户表)的映射文件就给它取名为UserMapper.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">
<!--
在此映射文件中用于配置很多的sql语句
-->
<!--namespace命名空间 它的内容随便写 (不要问我为什么写com.deml.User 因为我喜欢!)-->
<mapper namespace="com.demo.User">
<!--select:查询标签 id用于唯一标识此sql语句 (随便取名字)
sql语句的大小写无所谓
#{}表示一个占位符
使用占位符之后要用 parameterType 指定输入参数的类型 应该与数据库中设置的类型相同
resultType表示sql输出结果所映射的Java对象类型(也就是这张表所对应的类)
-->
<select id="findById" parameterType="int" resultType="com.demo.User">
SELECT * FROM User WHERE userid=#{id}
</select>
<!--${}:表示拼接字符串 将接收到的参数的内容不加任何修饰拼接在sql中
由此可知 ${}有sql注入的风险 在此例如:输入的是:" or 1=1 "
${value}:接受输入参数的内容,如果传入类型是简单类型,则只能使用value
-->
<select id="findUserByName" resultType="com.demo.User">
select * from user where username like "%${value}%"
</select>
<!--添加用户-->
<insert id="insertUser1" parameterType="com.demo.User">
insert into user value (#{userName},#{password},#{userId})
</insert>
<!--添加用户并将插入数据的主键值返回 返回给表相对应的对象(只适用于主键值设置成了自增时的情况)
因为如果在数据库中主键设置成了自增,那么就会按照这个去给主键赋值。在对象中给主键符的值是没有用的
keyProperty:将查询的主键值设置到parameterType指定的对象的哪个属性
order: 相对于insert语句的select LAST_INSERT_ID()的执行顺序
resultType:指定select LAST_INSERT_ID()的结果类型
-->
<insert id="insertUser2" parameterType="com.demo.User">
<selectKey keyProperty="userId" order="AFTER" resultType="java.lang.Integer">
select LAST_INSERT_ID()
</selectKey>
insert into user value (#{userName},#{password},#{userId})
</insert>
<!--
查询返回非自增的主键值
执行过程:通过uuid()得到主键,
然后将主键值设置到user对象的userId属性中,
之后,在insert执行时,从user对象中取出userId属性值
-->
<insert id="insertUser3" parameterType="com.demo.User">
<selectKey keyProperty="userId" order="BEFORE" resultType="java.lang.Integer">
select uuid()
</selectKey>
insert into user value (#{userName},#{password},#{userId})
</insert>
<!--根据userId删除用户-->
<delete id="deleteById" parameterType="java.lang.Integer">
delete from user where userid=#{userid}
</delete>
<!--更新用户
-->
<update id="updateById" parameterType="com.demo.User">
update user set username=#{userName} where userid=#{userId}
</update>
</mapper>
5.创建接口
每一张表对应一个接口(其实创建接口可以把和创建表所对应的dao层的类统称为一个操作)。因为创建接口的目的就是为了给接下来创建类提供一个模板,让类去实现它,以便于后期维护起来方便。这里的接口创建如下:
/**
* Create by ZwZ
* DateTime:2018/10/2 11:49
* Description :
*/
public interface User {
void insertUser(User user) throws Exception;//添加用户信息
void deleteUser(int userId) throws Exception;//删除用户信息
void updateUser(int userId) throws Exception;//根据id修改用户信息
com.demo.User findUserById(int userId) throws Exception;//根据id查询用户信息
}
如何深入理解创建接口和dao层的意义:
6.创建dao层接口的实现类
创建了接口之后,就要创建接口的实现类:
package dao.impi;
// .::::.
// .::::::::.
// :::::::::::
// ..:::::::::::'
// '::::::::::::'
// .::::::::::
// '::::::::::::::..
// ..::::::::::::.
// ``::::::::::::::::
// ::::``:::::::::' .:::.
// ::::' ':::::' .::::::::.
// .::::' :::: .:::::::'::::.
// .:::' ::::: .:::::::::' ':::::.
// .::' :::::.:::::::::' ':::::.
// .::' ::::::::::::::' ``::::.
// ...::: ::::::::::::' ``::.
// ```` ':. ':::::::::' ::::..
// '.:::::' ':'````..
import dao.jiekou.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
/**
* Create by ZwZ
* DateTime:2018/10/2 11:56
* Description :
*/
public class UserImpl implements User {
private SqlSessionFactory sqlSessionFactory;
//通过构造方法注入SqlSessionFactory对象
public UserImpl(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public void insertUser(User user) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.insert("com.demo.User.insertUser2",user);
sqlSession.commit();
sqlSession.close();
}
@Override
public void deleteUser(int userId) throws Exception {
}
@Override
public void updateUser(int userId) throws Exception {
}
@Override
public com.demo.User findUserById(int userId) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
com.demo.User user = sqlSession.selectOne("com.demo.User.findById",userId);
sqlSession.commit();
sqlSession.close();
return user;
}
}
7.在总的配置文件中映射上表所对应的类的映射文件
其目的就是告诉mybatis : 我这里有一个映射文件,到时候加载的时候加载上。
方法:在SqlMapConfig.xml的<configuration>标签中的末尾加上以下代码
<!--加载映射文件-->
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
8.测试运行
package com.Test;
// .::::.
// .::::::::.
// :::::::::::
// ..:::::::::::'
// '::::::::::::'
// .::::::::::
// '::::::::::::::..
// ..::::::::::::.
// ``::::::::::::::::
// ::::``:::::::::' .:::.
// ::::' ':::::' .::::::::.
// .::::' :::: .:::::::'::::.
// .:::' ::::: .:::::::::' ':::::.
// .::' :::::.:::::::::' ':::::.
// .::' ::::::::::::::' ``::::.
// ...::: ::::::::::::' ``::.
// ```` ':. ':::::::::' ::::..
// '.:::::' ':'````..
import com.demo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
/**
* Create by ZwZ
* DateTime:2018/10/1 21:25
* Description :通过用户id查询用户
*/
public class Test1 {
public static void main(String[] args) throws IOException {
//mybatis的总配置文件
String resource = "SqlMapConfig.xml";
//得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建会话工厂,传入mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
/*通过工厂得到SqlSession*/
SqlSession sqlSession = sqlSessionFactory.openSession();
/*通过SqlSession操作数据库
* 第一个参数:映射文件中statement的id 等于 namespace+"."+statement的id
* 第二个参数:指定和映射文件中所匹配的parameterType类型的参数
* selectOne()表示查询出一条记录
*/
User user = sqlSession.selectOne( "com.demo.User.findById",1);
System.out.println(user.getUserName());
//释放资源
sqlSession.close();
}
}
对以上整个步骤进行穿通:
原始dao开发方式的弊端:
- dao接口实现类方法中存在大量重复代码,从设计上来看,应该抽取
- 调用sqlSession方法时,将satement的id硬编码了,即类似于"com.demo.User.findById"这种,都写死了。
- sqlSession的方法中,第二个参数要求传入的参数是Object类型,如果传错了参数,编译不会报错执行的时候才会报错,降低了开发效率,不利于开发。