Spring MVC 连接 MySQL 数据库 Hibernate

在上一篇博客《Spring MVC 连接 MySQL 数据库 JDBC》中介绍了在 Spring MVC 中使用 JDBC 来链接数据库。JDBC 可以说是访问数据库的最原始、最直接的方法。这种方式的特点是运行效率高,而缺点是程序代码中嵌入大量的 SQL 语句,使得项目难以维护,虽然 MVC 的分层结构把数据持久层单独出来,把数据库访问操作封装起来,业务层只需调用 API 就可以了。但是,如果数据模型非常复杂,代码量较大,特别是访问字段较多的表的时候,代码显得繁琐、累赘,容易出错,就需要非常专业和有经验的开发人员来开发,还需要有足够的时间。

开发人员不是只需要专注于业务逻辑的实现吗?有没有中间件可以做这个事情呢?是的,目前已经有好多种现成的持久化中间件可以选择,有:Hiherante,TopLink,JDO等,其中 Hiberante 最受欢迎,它是基于 Java 的开发源代码的持久化中间件,对 JDBC 做了轻量级封装,不仅提供了 ORM 映射服务,还提供数据查询和缓存功能,开发人员可以方便地通过它提供的 API 来操纵数据库。大大减少了开发的工作量,降低了持久化层开发的门槛。

我们还是通过项目来学习简单的 Hiberante 链接 MySQL 数据库。可以使用上次的 spring-mvc-mysql 项目 JDBC 分支,修改 Dao 持久化层就可以了,这就是 MVC 分层结构的强大之处。

pom.xml

添加 Hiberante 所需的依赖

1
2
3
4
5
6
7
8
9
10
11
<!-- Hibernate -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>

DataBaseConfig

添加 Hibernate 事务管理器和 SessionFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
@Configuration
@PropertySource("classpath:config/application.properties")
public class DataBaseConfig {
private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";
private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_HIBERNATE_FORMAT_SQL = "hibernate.format_sql";
private static final String PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO = "hibernate.hbm2ddl.auto";
private static final String PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY = "hibernate.ejb.naming_strategy";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
private static final String PROPERTY_NAME_ENTITY_MANAGER_PACKAGES_TO_SCAN = "entity.manager.packages.to.scan";
@Resource
private Environment environment;
/**
* Configures the data source.
*
* @return DataSource.
*/
@Bean
public DataSource dataSource() {
final HikariDataSource dataSource = new HikariDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
dataSource.setJdbcUrl(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
dataSource.setUsername(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
dataSource.setPassword(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
return dataSource;
}
/**
* Spring JDBC Template
*
* @return JdbcTemplate
*/
@Bean
public JdbcTemplate jdbcTemplate() {
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource());
return jdbcTemplate;
}
/**
* SessionFactory
*
* @return LocalSessionFactoryBean
*/
@Bean
public LocalSessionFactoryBean sessionFactory(){
LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
localSessionFactoryBean.setPackagesToScan(environment.getRequiredProperty(PROPERTY_NAME_ENTITY_MANAGER_PACKAGES_TO_SCAN));
localSessionFactoryBean.setDataSource(dataSource());
Properties hibernateProperties = new Properties();
hibernateProperties.put(PROPERTY_NAME_HIBERNATE_DIALECT, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
hibernateProperties.put(PROPERTY_NAME_HIBERNATE_FORMAT_SQL, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_FORMAT_SQL));
hibernateProperties.put(PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO));
hibernateProperties.put(PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY,
environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_NAMING_STRATEGY));
hibernateProperties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
hibernateProperties.put("hibernate.connection.CharSet", "UTF-8");
hibernateProperties.put("hibernate.connection.characterEncoding", "UTF-8");
hibernateProperties.put("hibernate.connection.useUnicode", "true");
localSessionFactoryBean.setHibernateProperties(hibernateProperties);
return localSessionFactoryBean;
}
/**
* Transactio``` javanManager
*
* @return HibernateTransactionManager
*/
@Bean
public HibernateTransactionManager transactionManager() {
HibernateTransactionManager hibernateTransactionManager = new HibernateTransactionManager();
hibernateTransactionManager.setSessionFactory(sessionFactory().getObject());
return hibernateTransactionManager;
}
}

application.properties

添加 Hiberante 配置

1
2
3
4
5
6
7
8
9
10
### Hibernate
hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
hibernate.format_sql=false
hibernate.hbm2ddl.auto=update
hibernate.ejb.naming_strategy=org.hibernate.cfg.ImprovedNamingStrategy
hibernate.show_sql=false
hibernate.database=MYSQL
### Entity.Manager
entity.manager.packages.to.scan=com.aidansu.demo.model

Model

给 User 类添加注解,删除 UserMapper 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
@Entity
@Table(name="t_user")
public class User implements Serializable{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private String telephone;
@Column(name="create_time")
private Date createTime;
@Column(name="last_login_time")
private Date lastLoginTime;
@Column(name="update_time")
private Date updateTime;
public User() {
}
public User(String username, String password, String telephone, Date createTime, Date lastLoginTime, Date updateTime) {
this.username = username;
this.password = password;
this.telephone = telephone;
this.createTime = createTime;
this.lastLoginTime = lastLoginTime;
this.updateTime = updateTime;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getTelephone() {
return telephone;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getLastLoginTime() {
return lastLoginTime;
}
public void setLastLoginTime(Date lastLoginTime) {
this.lastLoginTime = lastLoginTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
}

Dao

创建一个 Hibernate 执行方法基础抽象类,封装了对象的增、删、查、改等操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
public abstract class BaseDAOHibernate<T, ID extends Serializable> {
@Autowired
private SessionFactory sessionFactory;
/**
* 获取模型类的抽象方法
*
* @return 返回具体实现的模型类
*/
protected abstract Class<?> getModelClass() ;
protected Session getSession(){
return sessionFactory.openSession();
}
/**
* 创建或更新对象
*
* @param obj 需要创建或更新的对象
*/
protected void doCreateOrUpdateObject(Object obj) {
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.saveOrUpdate(obj);
tx.commit();
session.close();
}
/**
* 创建对象
*
* @param obj 需要创建的对象
* @return 返回创建对象ID
*/
protected Serializable doCreateObject(Object obj) {
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Serializable serializable = session.save(obj);
tx.commit();
session.close();
return serializable;
}
/**
* 更新对象
*
* @param obj 需要更新的对象
*/
protected void doUpdateObject(Object obj) {
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.update(obj);
tx.commit();
session.close();
}
/**
* 删除对象
*
* @param obj 需要删除的对象
*/
protected void doDeleteObject(Object obj) {
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.delete(obj);
tx.commit();
session.close();
}
/**
* 根据id查找对象
*
* @param id 需要查找的对象ID
* @return 需要查找的对象
*/
protected Object doFindObjectById(Serializable id) {
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Object object = session.get(this.getModelClass(), id);
tx.commit();
session.close();
return object;
}
/**
* 根据id查找指定对象
*
* @param clazz 指定需查找的对象类
* @param id 需要查找的对象ID
* @return 需要查找的对象
*/
protected Object doFindObjectById(Class<?> clazz, Serializable id) {
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Object object = session.get(clazz, id);
tx.commit();
session.close();
return object;
}
/**
* 查找所有对象
*
* @return 需要查找的对象列表
*/
protected List<T> doFindObjects() {
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Query query = session.createQuery("from "+getModelClass().getName());
List<T> list = query.list();
tx.commit();
session.close();
return list;
}
/**
* 统计某个对象集合的总数
*
* @return 记录总数
*/
protected int doCountObject() {
int result ;
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
String hql = "select count(*) from " + getModelClass().getName();
Query query = session.createQuery(hql);
Long resultLonger = (Long) query.list().get(0);
result = resultLonger.intValue();
tx.commit();
session.close();
return result;
}
/**
* 通过HQL,根据模糊查询条件,统计记录数
*
* @param properties 对象属性
* @param values 需要查询的对象属性对应的值条件
* @return 统计数
*/
protected int doHQLCountObject(String[] properties, Object[] values) {
int result = 0;
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
String hql = "select count(*) from " + this.getModelClass().getName()+ " where 1=1 ";
//组装hql条件字符串
for (int i = 0; i < properties.length; i++) {
if (i == 0)
hql += " and " + properties[i] + " like :" + properties[i] ;
else
hql += " or " + properties[i] + " like :" + properties[i] ;
}
Query query = session.createQuery(hql);
//设置查询条件值
for (int i = 0; i < properties.length; i++) {
query.setParameter(properties[i] , "%" + values[i] + "%");
}
Long resultLonger = (Long) query.list().get(0);
result = resultLonger.intValue();
tx.commit();
session.close();
return result;
}
}

修改 UserDAOImpl 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
@Repository("UserDAO")
public class UserDAOImpl extends BaseDAOHibernate implements UserDAO{
@Override
protected Class<User> getModelClass() {
return User.class;
}
@Override
public void insert(User user) {
doCreateObject(user);
}
@Override
public void update(User user) {
doUpdateObject(user);
}
@Override
public void delete(long id) {
doDeleteObject( findById( id ) ) ;
}
@Override
public User findById(long id) {
return (User)doFindObjectById(id);
}
@Override
public User findByUsername(String username) {
Session session = null;
Transaction tx = null;
User user = null;
try{
session = super.getSession();
tx = session.beginTransaction();
String hql = "from User where username=? order by id desc";
user = (User)session.createQuery(hql).setParameter(0,username).setMaxResults(1).uniqueResult();
tx.commit();
}catch(HibernateException he){
if(tx!=null){
tx.rollback();
}
he.printStackTrace();
}finally{
if(session!=null)
session.close();
}
return user;
}
@Override
public List<User> findAll() {
return (List<User>)doFindObjects();
}
}

Run

需要在 Tomcat 容器上运行,点击 Run,服务器就会启动在 http://localhost:8080 端口上。

本次项目 spring-mvc-mysql 的项目代码已经放在 github 上,有需要的同学可以下载查看。地址: https://github.com/aidansu/spring-mvc-mysql/tree/Hibernate 分支 Hiberante

完!

坚持原创技术分享,您的支持将鼓励我继续创作!