Java Web --- Mybatis 框架搭建实例
前言
MyBatis是一个优秀的持久层框架。原生的jdbc操作存在大量的重复性代码(如注册驱动,创建连接,创建statement,结果集检测等)。框架的作用就是把这些繁琐的代码封装。
MyBatis通过XML或者注解的方式将要执行的sql语句配置起来,并通过java对象和sql语句映射成最终执行的sql语句。最终由MyBatis框架执行sql,并将结果映射成java对象并返回。
正文
准备jar包
- mybatis-3.4.6.jar
- mysql-connector-java-5.1.47.jar
mysql数据库为firstdb,表名为xtb,表结构如下
1.新建java project MybatisPro ,项目结构图:
一共五个文件
在src下新建com.domain包,在新建User.java
-
package com.domain;
-
public class User {
-
private Integer user_id;
-
private String user_name;
-
private String user_sex;
-
private String user_phone;
-
public String toString() {
-
return "User [user_id=" + user_id + ", user_name=" + user_name + ", user_sex=" + user_sex + ", user_phone="
-
+ user_phone + "]";
-
}
-
public String getUser_phone() {
-
return user_phone;
-
}
-
public void setUser_phone(String user_phone) {
-
this.user_phone = user_phone;
-
}
-
public String getUser_sex() {
-
return user_sex;
-
}
-
public void setUser_sex(String user_sex) {
-
this.user_sex = user_sex;
-
}
-
public String getUser_name() {
-
return user_name;
-
}
-
public void setUser_name(String user_name) {
-
this.user_name = user_name;
-
}
-
public Integer getUser_id() {
-
return user_id;
-
}
-
public void setUser_id(Integer user_id) {
-
this.user_id = user_id;
-
}
-
}
在src下新建com.Dao包,然后新建Interface文件,UserMapper.java
-
package com.Dao;
-
import com.domain.*;
-
public interface UserMapper {
-
public User findUserById(int id) throws Exception;
-
public void insertUser(User user) throws Exception;
-
}
在src下新建全局配置文件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>
-
<environments default="development">
-
<environment id="development">
-
<transactionManager type="JDBC"/>
-
<dataSource type="POOLED">
-
<property name="driver" value="com.mysql.jdbc.Driver"/>
-
<property name="url" value="jdbc:mysql://localhost:3306/firstdb"/><!--用自己的数据库名字 -->
-
<property name="username" value="root"/> <!-- 用自己的用户名密码 -->
-
<property name="password" value=""/>
-
</dataSource>
-
</environment>
-
</environments>
-
<mappers>
-
<mapper resource="UserMapper.xml"/> <!-- 这里配置映射文件 -->
-
</mappers>
-
</configuration>
新建映射配置文件UserMpper.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">
-
<!-- mapper标签要指定namespace属性,不然会报错,可看做包名-->
-
<mapper namespace="com.Dao.UserMapper">
-
<select id="findUserById" parameterType="int" resultType="com.domain.User">
-
select * from xtb where user_id = #{id}
-
</select>
-
<insert id="insertUser" parameterType="com.domain.User">
-
insert into xtb(user_name,user_sex,user_phone) values(#{user_name},#{user_sex},#{user_phone})
-
</insert>
-
</mapper>
最后,新建测试类Test.java
-
package com.test;
-
import java.io.InputStream;
-
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 com.Dao.UserMapper;
-
import com.domain.User;
-
public class Test{
-
public static void main(String[] args) throws Exception {
-
testInsertUser();
-
SelectByid();
-
}
-
public static void SelectByid() throws Exception{
-
String resource = "SqlMapConfig.xml";
-
InputStream inputStream = Resources.getResourceAsStream(resource);
-
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
-
SqlSession session = factory.openSession();
-
//---------------
-
UserMapper userMapper = session.getMapper(UserMapper.class);
-
User user = userMapper.findUserById(2);
-
System.out.println(user);
-
//--------------
-
session.close();
-
}
-
public static void testInsertUser() throws Exception{
-
String resource = "SqlMapConfig.xml";
-
InputStream inputStream = Resources.getResourceAsStream(resource);
-
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
-
SqlSession session = factory.openSession();
-
//---------------------
-
User user = new User();
-
user.setUser_name("lalala");
-
user.setUser_sex("women");
-
user.setUser_phone("0123345");
-
UserMapper mapper = session.getMapper(UserMapper.class);
-
mapper.insertUser(user);
-
session.commit();
-
//----------------------
-
session.close();
-
}
-
}
运行程序,查看结果:
常见错误解决:
基本上都是UserMapper.xml和接口UserMap.java的对应关系没有配置好,我把UserMapper.xml和UserMap.java拼在一起可以看下自己的配置是否正确:
简单来说就是:接口的包名,类名,参数,返回值分别对应着映射文件的namespace,id,parameterType,resultType。
总结原理:
mybais运用了代理技术,实例化出接口UserMapper的实例,然后通过根据配置文件调用sql.
具体流程:
1.读取配置文件SqlMapConfig.xml 获取连数据库的相关信息
2.有了这些信息就能创建SqlSessionFactory
3.SqlSessionFactory建立SqlSession
4.SqlSession 通过代理创建出UserMapper接口的实例,并从userMapper.xml中读取信息
5.通过userMapper.xml中的信息,执行sql语句
6.返回结果,关闭session
********************************以下为Mybatis使用过程中的注意事项*********************************************
原文连接:https://www.cnblogs.com/pretty-boy/p/5306549.html
使用Mybatis时请注意这两个参数,否则会让你的数据库连接爆掉
目前正在开发一个产品的服务器端代码,持久层我选择了Mybatis3(也就是原来的ibatis)作为框架,之所以选择他理由就是我觉得Hibernate搞起来貌似很复杂,我不太会用,哈哈(上家公司留下的阴影,用Hibernate搞得我想死)。上周完成了大部分代码的开发工作,想着既然是要发布的产品,于是找来Jmeter做压力测试,结果这一测,暴露问题了,mysql返回"too many connections"这个error,这个error的具体解释参照这个链接http://dev.mysql.com/doc//refman/5.5/en/too-many-connections.html。
一般持久层与数据库连接都会通过一个连接池(pooled datasource)管理,方便复用连接,控制并发,比较有名的有DBCP,C3P0,BONECP等等。Mybatis3自己实现了一个连接池,在配置文件中指定datasource的type属性为POOLED即可使用。与并发关系较大的两个Mybatis连接池参数是poolMaximumActiveConnections和poolMaximumIdleConnections。
好了,出了问题,自然得找文档(官方手册,中英文皆有),poolMaximumActiveConnections是最大的活动连接数,活动连接,顾名思义,就是正在与数据库交互的连接,默认是10,poolMaximumIdleConnections是空闲连接数,就是没有处理请求的连接,默认是5。Mysql的max_connections我设置的是200,既最大连接数。这样一看,好像找不到问题所在,连接池最大的活动连接也就是10,跟200比还差很远,Mysql怎么会返回"too many connections"呢?在查阅文档无果后,我请教周围的一位同事,他虽然没用过Mybatis,但是他说是不是请求数超过poolMaximumActiveConnections后mybatis还会去获取连接,是不是有这样的参数控制,然后让我看看源码,说开源的东西嘛,搞不清楚就看源码。
我一向对源码抱有恐惧的心理,感觉那都是大神写的,我等屌丝怎能看得懂,不过被逼无奈,翻出Mybatis的源码看了一看,结果豁然开朗。找到org.apache.ibatis.datasource.pooled包下面的PooledDataSource类,这个就是连接池的实现类。可以看到里面定义了几个参数,其中就包括poolMaximumActiveConnections和poolMaximumIdleConnections,找到pushConnection方法,这个方法里会判断当前空闲连接数和poolMaximumIdleConnections的大小,如果小于他,会new PooledConnection并放进队列中,这就导致一个问题,当所有的连接被占满后,Mybatis为了保持一定的空闲连接,会不断获取新的连接,然后这些新连接被占用后,就会再去new PooledConnection,结果就是超过了mysql设置的最大连接数,然后数据库返回该错误。不知道这算不算是Mybatis的一个"坑"吧,总之在使用时要小心了,并发量大的时候就会爆掉你的数据库,解决办法很简单,将poolMaximumIdleConnections设置为0即可,果然改掉后压力测试不会爆掉数据库。
现在回想起来,官方文档对poolMaximumIdleConnections的定义是:在任意时间存在的空闲连接数,完全就解释了这个参数的含义,只不过当时没有仔细想,那这个参数是不是该改名字叫poolPermanentIdleConnections比较好呢,呵呵。
问题解决了,很开心,晚上回去再仔细读下里面的源码,看看还有没有别的没发现的问题。看来源码也不是想象中的那么神秘和高深啊。其实为什么那个同事一下就能看出问题的大概,一方面是经验丰富,另一方面可能与他理解数据库连接池机制有关,归根到底,基础的东西还是最重要的。
回去认真读了Mybatis源码,发现自己错了,特此更正,以免误导读者,实在是对不起。其实poolMaximumActiveConnections的存在可以正确地限制数据库连接池并发访问数据的连接数,没有问题,之所以我的数据库爆掉了,是我没有正确地维持SqlSessionFactory这个类的一个单例。在使用时一定要保持一个全局唯一的SqlSessionFactory