一、JDBC的问题
1、数据库连接创建、释放频繁造成系统资源浪费,从而影响系统性能。如果使用数据库连接池可解决此问题。
2、Sql语句在代码中硬编码,造成代码不易维护,实际应用中sql变化的可能较大,sql变动需要改变java代码。
3、使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。
4、对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。
二、什么是MyBatis?
1、Mybatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
2、Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
3、Mybatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。 MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及对结果集的检索。 MyBatis 可以使用简单的XML 或注解用于配置和原始映射,将接口和 Java 的 POJO( Plain Old Java Objects,普通的Java 对象)映射成数据库中的记录.
4、Mybatis 目前提供了三种语言实现的版本,包括:Java、.NET以及Ruby。(我们讲java的使用)
三、Mybatis架构
1、Mybatis配置
SqlMapConfig.xml文件(名称可变),此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
mapper.xml文件:即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
2、通过Mybatis环境等配置信息构造SqlSessionFactory即会话工厂
3、由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
4、Mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
5、Mapped Statement也是 Mybatis一个底层封装对象,它包装了Mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
6、Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
7、Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。
四、Mybatis框架开发环境搭建
1、eclipse中加入mybatis的约束文件:
(1)location : mybatis-3-config.dtd
key:http://mybatis.org/dtd/mybatis-3-config.dtd
(2)location :mybatis-3-mapper.dtd
key:http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd
2、导包:
mybatis-*.*.*.jar 、数据库驱动包、日志包
五、简单例子(快速入门)---(Eclipse2008.9+jdk10.0+maven+mysql8.0+mybatis3)
1、目录结构如下:
2、在描述文件(pom.xml)中导入jar包:
mysql-connector-java-8.0.11
mybatis-3.4.6
l og4j-1.2.17:实现日志的.class文件
log4j-core-2.11.1:日志文件的源码,即 .class与.java文件
log4j-api-2.11.1: 具体接口的定义
slf4j-log4j12-1.7.25: 是众多日志接口的集合,它不负责具体的日志实现,只在编译时负责寻找合适的日志系统进行绑定。
asm-commons-3.3.1: ASM字节码库, ASM做的事情一定程度上正是javac解释器做的工作
javassist-3.17.1-GA: 是一款字节码编辑工具,可以直接编辑和生成Java生成的字节码,以达到对.class文件进行动态修改的效果
3、在mysql找创建数据库(MVC)、数据表:
CREATE TABLE `tb_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(20) DEFAULT NULL,
`password` varchar(20) DEFAULT NULL,
`gender` varchar(2) DEFAULT NULL,
`email` varchar(20) DEFAULT NULL,
`province` varchar(30) DEFAULT NULL,
`city` varchar(30) DEFAULT NULL,
`birthday` date DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=8 DEFAULT CHARSET=utf8
4、在 src/main/resources下创建资源文件mysql.properties用于连接数据库
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mvc?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8
jdbc.username=root
jdbc.password=admin
5、 在src/main/resources下创建资源文件log4j.properties用于日志管理:
log4j.rootLogger = debug,stdout
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{ yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
6、创建实体类(POJO):
public class User implements Serializable{
private Integer id;
private String username;
private String password;
private String gender;
private String email;
private String province;
private String city;
private Date birthday;
//省去set/get方法
}
7、创建数据库操作的接口(UserMapper.java):
public interface UserMapper {
public int insertUser(User user) throws Exception;//新增用户
public int updateUser (User user,int id) throws Exception;//更新用户
public int deleteUser(Integer id) throws Exception;//删除用户
public User selectUserById(Integer id) throws Exception;//按id查询
public List<User> selectAllUser() throws Exception;//查询所有
}
8、创建sql映射文件(UserMapper.xml):
<mapper namespace="com.mybatis.mapper.UserMapper">
<!-- 自定义返回结果集 -->
<resultMap type="User" id="userMap">
<id property="id" column="id" javaType="java.lang.Integer"/>
<result property="username" column="username" javaType="java.lang.String"/>
<result property="password" column="password" javaType="java.lang.String"/>
<result property="gender" column="gender" javaType="java.lang.String"/>
<result property="email" column="email" javaType="java.lang.String"/>
<result property="province" column="province" javaType="java.lang.String"/>
<result property="city" column="city" javaType="java.lang.String"/>
<result property="birthday" column="birthday" javaType="java.util.Date"/>
</resultMap>
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
insert into tb_user(username,password,gender,email,province,city,birthday) values(#{ username},#{password},#{gender},#{email},#{province},#{city},#{birthday})
</insert>
<update id="updateUser">
update tb_user set username=#{ username},password=#{password},gender=#{gender},email=#{email},province=#{province},city=#{city},birthday=#{birthday} where id=#{id}
</update>
<delete id="deleteUser" parameterType="Integer">
delete from tb_user where id=#{id}
</delete>
<select id="selectUserById" parameterType="Integer" resultMap="userMap">
select * from tb_user where id=#{id}
</select>
<select id="selectAllUser" resultMap="userMap">
select * from tb_user
</select>
</mapper>
9、创建Mybatis全局配置文件(mybatis-config.xml):
<configuration>
<!-- 引用外部配置文件 -->
<properties resource="mysql.properties"></properties>
<!-- 为JavaBean起别名 -->
<!-- 别名方式1,一个一个的配置 type中放置的是类的全路径,alias中放置的是类别名
<typeAliase type="com.mybatis.beans.User" alias="User"/> -->
<!-- 别名方式2,自动扫描,将JAVA类的类名作为类的类别名
<package name="com.mybatis.beans"/>
-->
<typeAliases>
<typeAlias type="com.mybatis.beans.User" alias="User"/>
</typeAliases>
<!-- 配置mybatis运行环境 -->
<environments default="cybatis">
<environment id="cybatis">
<!-- 配置事务管理器
type="JDBC" 使用JdbcTransactionFactory事务工厂独立管理事务,直接使用JDK提供的JDBC来管理事务的各
个环节:提交、回滚、关闭等操作;
type="MANAGED"使用ManagedTransactionFactory事务工厂,MyBatis不在ORM层管理事务,而是交给容器(Tomcat、JBOSS)去管理
-->
<transactionManager type="JDBC"/>
<!-- 配置数据源 -->
<!--
mybatis提供了3种数据源类型,分别是:POOLED,UNPOOLED,JNDI
POOLED 表示支持JDBC数据源连接池
UNPOOLED 表示不支持数据源连接池
JNDI 表示支持外部数据源连接池
-->
<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>
<!-- 配置映射方式 -->
<!--
方式1:一个一个的配置
<mapper resource="com/cy/mybatis/mapper/UserMapper.xml"/>
方式2:自动扫描包内的Mapper接口与配置文件
<package name="com/mybatis/mapper"/>
-->
<mappers>
<mapper resource="com/mybatis/mapper/UserMapper.xml"/>
</mappers>
</configuration>
10、创建工具类(DBTools.java)用于获取session
public class DBTools {
private static SqlSessionFactory sessionFactory;
static {
try {
//使用MyBatis提供的Resources类加载mybatis的配置文件
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
//构建sqlSession的工厂
sessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSession() {
return sessionFactory.openSession();
}
}
11、测试类:
public class UserService {
private static Logger logger = LoggerFactory.getLogger(UserService.class);
//添加信息
private static boolean inserUser() {
SqlSession session = DBTools.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
boolean bool = false;
User u = null;
try {
u = new User(null, "张三", "12345","男","1234@qq.com", "AAAA", "西安",dateFormat.parse("2001-12-12"));
} catch (ParseException e1) {
e1.printStackTrace();
}
try {
int index=mapper.insertUser(u);
bool=index>0?true:false;
logger.error("新增用户user对象:{},操作状态:{}",new Object[]{ u,bool});
session.commit();
return bool;
} catch (Exception e) {
e.printStackTrace();
session.rollback();
return false;
}finally{
session.close();
}
}
//删除记录
private static boolean deleteUser(Integer id) {
SqlSession session = DBTools.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
boolean bool = false;
try {
int index = mapper.deleteUser(id);
bool = index>0?true:false;
logger.debug("根据用户id:{},操作状态{}",new Object[]{ id,bool});
session.commit();
return bool;
} catch (Exception e) {
e.printStackTrace();
session.rollback();
return false;
}finally {
session.close();
}
}
//按id查询
private static void selectUserById(int id){
SqlSession session=DBTools.getSession();
UserMapper mapper=session.getMapper(UserMapper.class);
try {
User user= mapper.selectUserById(id);
logger.debug("根据用户Id:{},查询用户信息:{}",new Object[]{ id,user});
session.commit();
} catch (Exception e) {
e.printStackTrace();
session.rollback();
}finally{
session.close();
}
}
//查询所有用户
private static void selectAllUser(){
SqlSession session=DBTools.getSession();
UserMapper mapper=session.getMapper(UserMapper.class);
try {
List<User> user=mapper.selectAllUser();
logger.debug("获取所用的用户:{}",user);
session.commit();
} catch (Exception e) {
e.printStackTrace();
session.rollback();
}finally{
session.close();
}
}
public static void main(String[] args) {
//inserUser();
selectAllUser();
}
}